mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inference: skip lambda content and all its dependants when lambda type parameter type is calculated
This commit is contained in:
@@ -17,6 +17,8 @@ package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.RecursionGuard;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
@@ -35,6 +37,7 @@ import java.util.*;
|
||||
* Date: 7/17/12
|
||||
*/
|
||||
public class LambdaUtil {
|
||||
public static final RecursionGuard ourParameterGuard = RecursionManager.createGuard("lambdaParameterGuard");
|
||||
public static ThreadLocal<Map<PsiElement, PsiType>> ourFunctionTypes = new ThreadLocal<Map<PsiElement, PsiType>>();
|
||||
private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName());
|
||||
|
||||
@@ -667,6 +670,10 @@ public class LambdaUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isLambdaParameterCheck() {
|
||||
return !ourParameterGuard.currentStack().isEmpty();
|
||||
}
|
||||
|
||||
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
|
||||
@@ -294,7 +294,9 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
if (!stackStamp.mayCacheNow() ||
|
||||
isOverloadCheck() ||
|
||||
!includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) ||
|
||||
getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent())) {
|
||||
getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent()) ||
|
||||
LambdaUtil.isLambdaParameterCheck()
|
||||
) {
|
||||
return inferredSubstitutor;
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +435,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null) {
|
||||
final PsiType[] expressionTypes = argumentList.getExpressionTypes();
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.navigation.ItemPresentationProviders;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.CheckUtil;
|
||||
import com.intellij.psi.impl.ElementPresentationUtil;
|
||||
@@ -67,8 +68,14 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
if (parameterIndex > -1) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
PsiType type = FunctionalInterfaceParameterizationUtil.getGroundTargetType(LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true), lambdaExpression);
|
||||
final PsiType functionalInterfaceType = LambdaUtil.ourParameterGuard.doPreventingRecursion(param, false,
|
||||
new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true);
|
||||
}
|
||||
});
|
||||
PsiType type = FunctionalInterfaceParameterizationUtil.getGroundTargetType(functionalInterfaceType, lambdaExpression);
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
|
||||
@@ -90,7 +90,7 @@ public class JavaResolveCache {
|
||||
}
|
||||
|
||||
//cache standalone expression types as they do not depend on the context
|
||||
final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck();
|
||||
final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck();
|
||||
if (isOverloadCheck && PsiPolyExpressionUtil.isPolyExpression(expr)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
+83
-45
@@ -361,11 +361,13 @@ public class InferenceSession {
|
||||
|
||||
if (parameters != null && args != null && !isOverloadCheck()) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
|
||||
final HashSet<ConstraintFormula> ignoredConstraints = new HashSet<ConstraintFormula>();
|
||||
if (parameters.length > 0) {
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), mySiteSubstitutor, additionalConstraints, properties.isVarargs(), initialSubstitutor);
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), mySiteSubstitutor, additionalConstraints,
|
||||
ignoredConstraints, properties.isVarargs(), initialSubstitutor);
|
||||
}
|
||||
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints, ignoredConstraints)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -416,21 +418,29 @@ public class InferenceSession {
|
||||
PsiMethod parentMethod,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
boolean varargs,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]);
|
||||
if (arg != null) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() && arg instanceof PsiLambdaExpression) {
|
||||
for (Object expr : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
|
||||
if (PsiTreeUtil.getParentOfType((PsiElement)expr, PsiLambdaExpression.class) == arg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiSubstitutor nestedSubstitutor = myInferenceSessionContainer.findNestedSubstitutor(arg, myInferenceSubstitution);
|
||||
final PsiType parameterType = nestedSubstitutor.substitute(getParameterType(parameters, i, siteSubstitutor, varargs));
|
||||
if (!isPertinentToApplicability(arg, parentMethod)) {
|
||||
if (arg instanceof PsiLambdaExpression) {
|
||||
for (Object expr : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
|
||||
if (PsiTreeUtil.getParentOfType((PsiElement)expr, PsiLambdaExpression.class) == arg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Object expr : LambdaUtil.ourParameterGuard.currentStack()) {
|
||||
if (expr instanceof PsiParameter && ((PsiParameter)expr).getDeclarationScope() == arg) {
|
||||
ignoredConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
|
||||
}
|
||||
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType));
|
||||
@@ -439,12 +449,12 @@ public class InferenceSession {
|
||||
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCall)arg);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCall)arg, initialSubstitutor);
|
||||
collectAdditionalConstraints(additionalConstraints, ignoredConstraints, (PsiCall)arg, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
else if (arg instanceof PsiLambdaExpression &&
|
||||
isPertinentToApplicability(arg, parentMethod)) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType,
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)arg, parameterType,
|
||||
!isProperType(initialSubstitutor.substitute(parameterType)),
|
||||
initialSubstitutor);
|
||||
}
|
||||
@@ -472,19 +482,22 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
PsiLambdaExpression lambdaExpression,
|
||||
PsiType parameterType,
|
||||
boolean addConstraint, PsiSubstitutor initialSubstitutor) {
|
||||
boolean addConstraint,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
|
||||
if (interfaceReturnType != null) {
|
||||
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
|
||||
for (PsiExpression returnExpression : returnExpressions) {
|
||||
processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, returnExpression, interfaceReturnType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
Set<ConstraintFormula> ignoredConstraints,
|
||||
PsiExpression returnExpression,
|
||||
PsiType functionalType,
|
||||
boolean addConstraint,
|
||||
@@ -493,7 +506,7 @@ public class InferenceSession {
|
||||
if (addConstraint) {
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression, initialSubstitutor);
|
||||
collectAdditionalConstraints(additionalConstraints, ignoredConstraints, (PsiCallExpression)returnExpression, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -501,19 +514,20 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
else if (returnExpression instanceof PsiParenthesizedExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
else if (returnExpression instanceof PsiConditionalExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
processReturnExpression(additionalConstraints, ignoredConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType, addConstraint, initialSubstitutor);
|
||||
}
|
||||
else if (returnExpression instanceof PsiLambdaExpression) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType, myErased, initialSubstitutor);
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)returnExpression, functionalType, myErased, initialSubstitutor);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints,
|
||||
final PsiCall callExpression,
|
||||
final Set<ConstraintFormula> ignoredConstraints,
|
||||
final PsiCall callExpression,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
@@ -524,7 +538,8 @@ public class InferenceSession {
|
||||
final PsiExpression[] newArgs = argumentList.getExpressions();
|
||||
final PsiParameter[] newParams = method.getParameterList().getParameters();
|
||||
if (newParams.length > 0) {
|
||||
collectAdditionalConstraints(newParams, newArgs, method, chooseSiteSubstitutor(properties, result, method), additionalConstraints, chooseVarargsMode(properties, result), initialSubstitutor);
|
||||
collectAdditionalConstraints(newParams, newArgs, method, chooseSiteSubstitutor(properties, result, method), additionalConstraints,
|
||||
ignoredConstraints, chooseVarargsMode(properties, result), initialSubstitutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1290,7 +1305,7 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean proceedWithAdditionalConstraints(Set<ConstraintFormula> additionalConstraints) {
|
||||
private boolean proceedWithAdditionalConstraints(Set<ConstraintFormula> additionalConstraints, Set<ConstraintFormula> ignoredConstraints) {
|
||||
//empty substitutor should be used to resolve input variables:
|
||||
//all types in additional constraints are already substituted during collecting phase,
|
||||
//recursive site substitutors (T -> List<T>) would make additional constraints work with multiple times substituted types, which is incorrect.
|
||||
@@ -1300,7 +1315,7 @@ public class InferenceSession {
|
||||
|
||||
while (!additionalConstraints.isEmpty()) {
|
||||
//extract subset of constraints
|
||||
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints);
|
||||
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints, ignoredConstraints);
|
||||
|
||||
//collect all input variables of selection
|
||||
final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>();
|
||||
@@ -1312,7 +1327,7 @@ public class InferenceSession {
|
||||
|
||||
final PsiSubstitutor substitutor = resolveSubsetOrdered(varsToResolve, siteSubstitutor);
|
||||
for (ConstraintFormula formula : subset) {
|
||||
if (!processOneConstraint(formula, additionalConstraints, substitutor)) return false;
|
||||
if (!processOneConstraint(formula, additionalConstraints, substitutor, ignoredConstraints)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1329,8 +1344,9 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private boolean processOneConstraint(ConstraintFormula formula,
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
PsiSubstitutor substitutor) {
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
PsiSubstitutor substitutor,
|
||||
Set<ConstraintFormula> ignoredConstraints) {
|
||||
|
||||
if (myContext instanceof PsiCall) {
|
||||
PsiExpressionList argumentList = ((PsiCall)myContext).getArgumentList();
|
||||
@@ -1348,27 +1364,20 @@ public class InferenceSession {
|
||||
if (formula instanceof ExpressionCompatibilityConstraint) {
|
||||
PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
PsiType parameterType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(((ExpressionCompatibilityConstraint)formula).getT(),
|
||||
(PsiLambdaExpression)expression);
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)expression, parameterType, !isProperType(parameterType), substitutor);
|
||||
PsiType parameterType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(((ExpressionCompatibilityConstraint)formula).getT(), (PsiLambdaExpression)expression);
|
||||
collectLambdaReturnExpression(additionalConstraints, ignoredConstraints, (PsiLambdaExpression)expression, parameterType, !isProperType(parameterType), substitutor);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<ConstraintFormula> buildSubset(final Set<ConstraintFormula> additionalConstraints) {
|
||||
private Set<ConstraintFormula> buildSubset(final Set<ConstraintFormula> additionalConstraints,
|
||||
final Set<ConstraintFormula> ignoredConstraints) {
|
||||
|
||||
final Set<InferenceVariable> outputVariables = getOutputVariables(additionalConstraints);
|
||||
final Set<InferenceVariable> ignoredOutputVariables = getOutputVariables(ignoredConstraints);
|
||||
|
||||
Set<ConstraintFormula> subset = new LinkedHashSet<ConstraintFormula>();
|
||||
final Set<InferenceVariable> outputVariables = new HashSet<InferenceVariable>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)constraint).getInputVariables(this);
|
||||
final Set<InferenceVariable> outputVars = ((InputOutputConstraintFormula)constraint).getOutputVariables(inputVariables, this);
|
||||
if (outputVars != null) {
|
||||
outputVariables.addAll(outputVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<ConstraintFormula> noInputVariables = new LinkedHashSet<ConstraintFormula>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
@@ -1382,11 +1391,13 @@ public class InferenceSession {
|
||||
final Set<InferenceVariable> dependencies = inputVariable.getDependencies(this);
|
||||
dependencies.add(inputVariable);
|
||||
if (!hasCapture(inputVariable)) {
|
||||
for (InferenceVariable outputVariable : outputVariables) {
|
||||
if (ContainerUtil.intersects(outputVariable.getDependencies(this), dependencies)) {
|
||||
dependsOnOutput = true;
|
||||
break;
|
||||
}
|
||||
if (dependsOnOutput(ignoredOutputVariables, dependencies)) {
|
||||
dependsOnOutput = true;
|
||||
ignoredConstraints.add(constraint);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
dependsOnOutput = dependsOnOutput(outputVariables, dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,7 +1425,10 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
if (subset.isEmpty()) {
|
||||
subset.add(additionalConstraints.iterator().next()); //todo choose one constraint
|
||||
additionalConstraints.removeAll(ignoredConstraints);
|
||||
if (!additionalConstraints.isEmpty()) {
|
||||
subset.add(additionalConstraints.iterator().next()); //todo choose one constraint
|
||||
}
|
||||
}
|
||||
|
||||
if (!noInputVariables.isEmpty()) {
|
||||
@@ -1425,6 +1439,30 @@ public class InferenceSession {
|
||||
return subset;
|
||||
}
|
||||
|
||||
private boolean dependsOnOutput(Set<InferenceVariable> outputVariables, Set<InferenceVariable> dependencies) {
|
||||
for (InferenceVariable outputVariable : outputVariables) {
|
||||
if (ContainerUtil.intersects(outputVariable.getDependencies(this), dependencies)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<InferenceVariable> getOutputVariables(Set<ConstraintFormula> constraintFormulas) {
|
||||
final Set<InferenceVariable> outputVariables = new HashSet<InferenceVariable>();
|
||||
for (ConstraintFormula constraint : constraintFormulas) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)constraint).getInputVariables(this);
|
||||
final Set<InferenceVariable> outputVars = ((InputOutputConstraintFormula)constraint).getOutputVariables(inputVariables, this);
|
||||
if (outputVars != null) {
|
||||
outputVariables.addAll(outputVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputVariables;
|
||||
}
|
||||
|
||||
public PsiSubstitutor collectApplicabilityConstraints(final PsiMethodReferenceExpression reference,
|
||||
final MethodCandidateInfo candidateInfo,
|
||||
final PsiType functionalInterfaceType) {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class InferenceSessionContainer {
|
||||
if (topLevelCall != null) {
|
||||
|
||||
final InferenceSession session;
|
||||
if (MethodCandidateInfo.isOverloadCheck() || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
session = startTopLevelInference(topLevelCall);
|
||||
}
|
||||
else {
|
||||
|
||||
+5
-5
@@ -134,9 +134,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
|
||||
if (method != null && !method.isConstructor()) {
|
||||
returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
else if (resolveResult != null) {
|
||||
final PsiClass psiClass = method != null ? method.getContainingClass() : (PsiClass)resolveResult.getElement();
|
||||
@@ -162,7 +160,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
return callSession;
|
||||
}
|
||||
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
if (returnType != null) {
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
}
|
||||
if (callSession.repeatInferencePhases()) {
|
||||
return callSession;
|
||||
}
|
||||
@@ -175,8 +175,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
session.registerIncompatibleErrorMessage(message);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
myArgumentsList.getText() + "; " +
|
||||
"file=" + (method == null ? "<unknown>" : method.getContainingFile()));
|
||||
}
|
||||
return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, true, new Computable<CandidateInfo>() {
|
||||
return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, false, new Computable<CandidateInfo>() {
|
||||
@Override
|
||||
public CandidateInfo compute() {
|
||||
return guardedOverloadResolution(conflicts);
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null && argumentList != null) {
|
||||
final PsiType[] expressionTypes = getExpressionTypes(argumentList);
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
if (MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Test {
|
||||
<K> void foo(Function<String, K> f1) {}
|
||||
|
||||
<T> Stream<T> bar(T ts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void f(){
|
||||
foo(y -> bar(y.to<caret>String()).map(a -> a.length()));
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
class StreamMainSimplified {
|
||||
public static void main(Optional<Map.Entry<Integer, String>> first) {
|
||||
String s1 = first.map((e) -> e.getV<caret>alue()).orElse("").substring(9);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -3,8 +3,8 @@ import java.util.*;
|
||||
class Main {
|
||||
|
||||
void foo(List<Integer> list) {
|
||||
bar(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar1(list, i -> i.intValue(), i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
bar1(list, i -> <error descr="Bad return type in lambda expression: int cannot be converted to S_OUT">i.intValue()</error>, i -> i.<error descr="Cannot resolve method 'unknown()'">unknown</error>());
|
||||
}
|
||||
|
||||
<U, S_IN, S_OUT, R> R bar(List<S_IN> list,
|
||||
|
||||
+9
@@ -36,3 +36,12 @@ final class Collectors {
|
||||
downstream.characteristics().toArray(new Collector.Characteristics[downstream.characteristics().size()]));
|
||||
}
|
||||
}
|
||||
|
||||
class SimplifiedTest {
|
||||
|
||||
public static void a(Stream<Integer> classifier) {
|
||||
flatMapping(classifier.map(k -> new AbstractMap.SimpleEntry<Integer, String>(k,k.toString())), Map.Entry::getKey);
|
||||
}
|
||||
|
||||
public static <U, R> void flatMapping(Stream<U> stream, Function<U, R> downstream) {}
|
||||
}
|
||||
|
||||
+12
-12
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
@@ -419,18 +420,17 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(tooltips.contains("<html><body><table border=0><tr><td>" +
|
||||
"<b>identity( ) </b></td><td colspan=1>in <b>Function</b> cannot be applied</td></tr><tr><td>to</td><td><b>()</b> " +
|
||||
|
||||
"</td></tr></table><br/>" +
|
||||
"reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>" +
|
||||
"</body></html>"));
|
||||
assertTrue(tooltips.contains(
|
||||
"<html><body><table border=0><tr><td>" +
|
||||
"<b>identity( ) </b></td><td colspan=1>in <b>Function</b> cannot be applied</td></tr><tr><td>to</td><td><b>()</b> " +
|
||||
"</td></tr></table><br/>" +
|
||||
"reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>" +
|
||||
"</body></html>"));
|
||||
boolean found = false;
|
||||
for (String tooltip : tooltips) {
|
||||
if (tooltip.contains("reason: no instance(s) of type variable(s) K, U exist so that Map<K, U> conforms to Function<U, V>")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fail(StringUtil.join(tooltips, ", "));
|
||||
}
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
|
||||
+8
@@ -63,6 +63,14 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testCacheUnresolvedMethods4() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testCacheUnresolvedMethods5() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testMethodOverloadsInsideLambdaHierarchy() throws Exception {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user