mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
lambda: take into account substitution interface with method -> functional interface;
do not infer return type parameters when lambda parameter type was calculated, no substitution caching here (IDEA-90875)
This commit is contained in:
+1
-1
@@ -268,7 +268,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
for (int i = 0; i < lambdaParameters.length; i++) {
|
||||
PsiParameter lambdaParameter = lambdaParameters[i];
|
||||
if (!TypeConversionUtil.isAssignable(resolveResult.getSubstitutor().substitute(parameters[i].getType()), lambdaParameter.getType())) {
|
||||
if (!TypeConversionUtil.isAssignable(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult).substitute(parameters[i].getType()), lambdaParameter.getType())) {
|
||||
myHolder.add(HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, lambdaParameter, incompatibleTypesMessage));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -340,10 +340,10 @@ public class GenericsUtil {
|
||||
}
|
||||
|
||||
public static PsiType eliminateWildcards(PsiType type) {
|
||||
return eliminateWildcardsInner(type, true);
|
||||
return eliminateWildcards(type, true);
|
||||
}
|
||||
|
||||
static PsiType eliminateWildcardsInner(PsiType type, final boolean eliminateInTypeArguments) {
|
||||
public static PsiType eliminateWildcards(PsiType type, final boolean eliminateInTypeArguments) {
|
||||
if (eliminateInTypeArguments && type instanceof PsiClassType) {
|
||||
PsiClassType classType = ((PsiClassType)type);
|
||||
JavaResolveResult resolveResult = classType.resolveGenerics();
|
||||
@@ -367,7 +367,7 @@ public class GenericsUtil {
|
||||
}
|
||||
}
|
||||
else if (type instanceof PsiArrayType) {
|
||||
return eliminateWildcardsInner(((PsiArrayType)type).getComponentType(), false).createArrayType();
|
||||
return eliminateWildcards(((PsiArrayType)type).getComponentType(), false).createArrayType();
|
||||
}
|
||||
else if (type instanceof PsiWildcardType) {
|
||||
final PsiType bound = ((PsiWildcardType)type).getBound();
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.*;
|
||||
*/
|
||||
public class LambdaUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName());
|
||||
public static ThreadLocal<Set<PsiParameterList>> ourParams = new ThreadLocal<Set<PsiParameterList>>();
|
||||
|
||||
@Nullable
|
||||
public static PsiType getFunctionalInterfaceReturnType(PsiLambdaExpression expr) {
|
||||
@@ -52,8 +53,12 @@ public class LambdaUtil {
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getFunctionalInterfaceMethod(PsiType functionalInterfaceType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiClass psiClass = resolveResult.getElement();
|
||||
return getFunctionalInterfaceMethod(PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getFunctionalInterfaceMethod(PsiClassType.ClassResolveResult result) {
|
||||
final PsiClass psiClass = result.getElement();
|
||||
if (psiClass != null) {
|
||||
final MethodSignature methodSignature = getFunction(psiClass);
|
||||
if (methodSignature != null) {
|
||||
@@ -63,6 +68,15 @@ public class LambdaUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PsiSubstitutor getSubstitutor(@NotNull PsiMethod method, @NotNull PsiClassType.ClassResolveResult resolveResult) {
|
||||
final PsiClass derivedClass = resolveResult.getElement();
|
||||
LOG.assertTrue(derivedClass != null);
|
||||
|
||||
final PsiClass methodContainingClass = method.getContainingClass();
|
||||
LOG.assertTrue(methodContainingClass != null);
|
||||
return TypeConversionUtil.getSuperClassSubstitutor(methodContainingClass, derivedClass, resolveResult.getSubstitutor());
|
||||
}
|
||||
|
||||
public static boolean isValidLambdaContext(PsiElement context) {
|
||||
return context instanceof PsiTypeCastExpression ||
|
||||
context instanceof PsiAssignmentExpression ||
|
||||
@@ -75,9 +89,10 @@ public class LambdaUtil {
|
||||
}
|
||||
|
||||
public static boolean isLambdaFullyInferred(PsiLambdaExpression expression, PsiType functionalInterfaceType) {
|
||||
if (expression.getParameterList().getParametersCount() > 0 || getFunctionalInterfaceReturnType(functionalInterfaceType) != PsiType.VOID) { //todo check that void lambdas without params check
|
||||
if (expression.getParameterList().getParametersCount() > 0 ||
|
||||
getFunctionalInterfaceReturnType(functionalInterfaceType) != PsiType.VOID) { //todo check that void lambdas without params check
|
||||
if (functionalInterfaceType instanceof PsiClassType && ((PsiClassType)functionalInterfaceType).isRaw()) return false;
|
||||
return !dependsOnTypeParams(functionalInterfaceType, expression);
|
||||
return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -126,11 +141,11 @@ public class LambdaUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isAcceptable(PsiLambdaExpression lambdaExpression, final PsiType leftType) {
|
||||
public static boolean isAcceptable(PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(leftType);
|
||||
final PsiClass psiClass = resolveResult.getElement();
|
||||
if (psiClass instanceof PsiAnonymousClass) {
|
||||
return isAcceptable(lambdaExpression, ((PsiAnonymousClass)psiClass).getBaseClassType());
|
||||
return isAcceptable(lambdaExpression, ((PsiAnonymousClass)psiClass).getBaseClassType(), checkReturnType);
|
||||
}
|
||||
final MethodSignature methodSignature = getFunction(psiClass);
|
||||
if (methodSignature == null) return false;
|
||||
@@ -149,16 +164,19 @@ public class LambdaUtil {
|
||||
}
|
||||
|
||||
if (!TypeConversionUtil.erasure(lambdaFormalType)
|
||||
.isAssignableFrom(TypeConversionUtil.erasure(GenericsUtil.eliminateWildcards(resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodParameterType)))))) {
|
||||
.isAssignableFrom(TypeConversionUtil.erasure(GenericsUtil.eliminateWildcards(
|
||||
resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodParameterType)))))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.assertTrue(psiClass != null);
|
||||
PsiType methodReturnType = getReturnType(psiClass, methodSignature);
|
||||
if (methodReturnType != null) {
|
||||
methodReturnType = resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
|
||||
return checkReturnTypeCompatible(lambdaExpression, methodReturnType) == null;
|
||||
if (checkReturnType) {
|
||||
LOG.assertTrue(psiClass != null);
|
||||
PsiType methodReturnType = getReturnType(psiClass, methodSignature);
|
||||
if (methodReturnType != null) {
|
||||
methodReturnType = resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
|
||||
return checkReturnTypeCompatible(lambdaExpression, methodReturnType) == null;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -274,6 +292,14 @@ public class LambdaUtil {
|
||||
return depends(type, param2Check, new TypeParamsChecker(expr));
|
||||
}
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiLambdaExpression lambdaExpression,
|
||||
PsiTypeParameter param2Check) {
|
||||
return depends(type, param2Check, new TypeParamsChecker(lambdaExpression,
|
||||
PsiUtil.resolveClassInType(functionalInterfaceType)));
|
||||
}
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiClass aClass,
|
||||
PsiMethod aMethod) {
|
||||
@@ -291,7 +317,10 @@ public class LambdaUtil {
|
||||
|
||||
public static boolean isFreeFromTypeInferenceArgs(final PsiParameter[] methodParameters,
|
||||
final PsiLambdaExpression lambdaExpression,
|
||||
final PsiExpression expression) {
|
||||
final PsiExpression expression,
|
||||
final PsiSubstitutor subst,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiTypeParameter typeParam) {
|
||||
if (expression instanceof PsiCallExpression && ((PsiCallExpression)expression).getTypeArguments().length > 0) return true;
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)expression).getClassOrAnonymousClassReference();
|
||||
@@ -300,16 +329,16 @@ public class LambdaUtil {
|
||||
if (parameterList != null) {
|
||||
final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements();
|
||||
if (typeParameterElements.length > 0) {
|
||||
if (!(typeParameterElements[0].getType() instanceof PsiDiamondType)){
|
||||
if (!(typeParameterElements[0].getType() instanceof PsiDiamondType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters();
|
||||
final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters();
|
||||
if (lambdaParams.length != methodParameters.length) return false;
|
||||
final boolean [] independent = new boolean[]{true};
|
||||
final boolean[] independent = new boolean[]{true};
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitConditionalExpression(PsiConditionalExpression expression) {
|
||||
@@ -335,7 +364,7 @@ public class LambdaUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (usedParamIdx > -1 && dependsOnTypeParams(methodParameters[usedParamIdx].getType(), lambdaExpression)) {
|
||||
if (usedParamIdx > -1 && dependsOnTypeParams(subst.substitute(methodParameters[usedParamIdx].getType()), functionalInterfaceType, lambdaExpression, typeParam)) {
|
||||
independent[0] = false;
|
||||
}
|
||||
}
|
||||
@@ -386,22 +415,21 @@ public class LambdaUtil {
|
||||
final PsiElement gParent = expressionList.getParent();
|
||||
if (gParent instanceof PsiCallExpression) {
|
||||
final PsiCallExpression contextCall = (PsiCallExpression)gParent;
|
||||
final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
|
||||
final PsiElement resolve = resolveResult.getElement();
|
||||
if (resolve instanceof PsiMethod) {
|
||||
final PsiParameter[] parameters = ((PsiMethod)resolve).getParameterList().getParameters();
|
||||
if (lambdaIdx < parameters.length) {
|
||||
if (!tryToSubstitute) {
|
||||
return parameters[lambdaIdx].getType();
|
||||
}
|
||||
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
|
||||
final PsiElement resolve = resolveResult.getElement();
|
||||
if (resolve instanceof PsiMethod) {
|
||||
final PsiParameter[] parameters = ((PsiMethod)resolve).getParameterList().getParameters();
|
||||
if (lambdaIdx < parameters.length) {
|
||||
if (!tryToSubstitute) return parameters[lambdaIdx].getType();
|
||||
return resolveResult.getSubstitutor().substitute(parameters[lambdaIdx].getType());
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,28 +454,38 @@ public class LambdaUtil {
|
||||
final int parameterIndex = ((PsiParameterList)paramParent).getParameterIndex(param);
|
||||
if (parameterIndex > -1) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
PsiType type = getFunctionalInterfaceType(lambdaExpression, true);
|
||||
if (type == null) {
|
||||
type = getFunctionalInterfaceType(lambdaExpression, false);
|
||||
}
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type);
|
||||
if (resolveResult != null) {
|
||||
final PsiMethod method = getFunctionalInterfaceMethod(type);
|
||||
if (method != null) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameterIndex < parameters.length) {
|
||||
final PsiType psiType = resolveResult.getSubstitutor().substitute(parameters[parameterIndex].getType());
|
||||
if (!dependsOnTypeParams(psiType, lambdaExpression)) {
|
||||
if (psiType instanceof PsiWildcardType) {
|
||||
final PsiType bound = ((PsiWildcardType)psiType).getBound();
|
||||
if (bound != null) {
|
||||
return bound;
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
Set<PsiParameterList> currentStack = ourParams.get();
|
||||
if (currentStack == null) {
|
||||
currentStack = new HashSet<PsiParameterList>();
|
||||
ourParams.set(currentStack);
|
||||
}
|
||||
|
||||
final PsiParameterList parameterList = lambdaExpression.getParameterList();
|
||||
try {
|
||||
currentStack.add(parameterList);
|
||||
PsiType type = getFunctionalInterfaceType(lambdaExpression, true);
|
||||
if (type == null) {
|
||||
type = getFunctionalInterfaceType(lambdaExpression, false);
|
||||
}
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type);
|
||||
if (resolveResult != null) {
|
||||
final PsiMethod method = getFunctionalInterfaceMethod(type);
|
||||
if (method != null) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameterIndex < parameters.length) {
|
||||
final PsiType psiType = getSubstitutor(method, resolveResult).substitute(parameters[parameterIndex].getType());
|
||||
if (!dependsOnTypeParams(psiType, type, lambdaExpression, null)) {
|
||||
return GenericsUtil.eliminateWildcards(psiType);
|
||||
}
|
||||
}
|
||||
return psiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
currentStack.remove(parameterList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,7 +495,7 @@ public class LambdaUtil {
|
||||
private static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
private final Set<PsiTypeParameter> myUsedTypeParams = new HashSet<PsiTypeParameter>();
|
||||
private final Set<PsiTypeParameter> myUsedTypeParams = new HashSet<PsiTypeParameter>();
|
||||
|
||||
private TypeParamsChecker(PsiMethod method, PsiClass aClass) {
|
||||
myMethod = method;
|
||||
@@ -465,7 +503,11 @@ public class LambdaUtil {
|
||||
}
|
||||
|
||||
public TypeParamsChecker(PsiLambdaExpression expression) {
|
||||
myClass = PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)).getElement();
|
||||
this(expression, PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)).getElement());
|
||||
}
|
||||
|
||||
public TypeParamsChecker(PsiLambdaExpression expression, PsiClass aClass) {
|
||||
myClass = aClass;
|
||||
PsiElement parent = expression.getParent();
|
||||
while (parent instanceof PsiParenthesizedExpression) {
|
||||
parent = parent.getParent();
|
||||
|
||||
@@ -15,19 +15,17 @@
|
||||
*/
|
||||
package com.intellij.psi.infos;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import com.intellij.util.containers.ConcurrentWeakHashMap;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author ik, dsl
|
||||
@@ -108,6 +106,12 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
}
|
||||
map.put(myArgumentList, getElement());
|
||||
try {
|
||||
|
||||
final Set<PsiParameterList> lists = LambdaUtil.ourParams.get();
|
||||
if (lists != null && !lists.isEmpty()) {
|
||||
return inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
}
|
||||
|
||||
myCalcedSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -648,7 +648,7 @@ public class TypeConversionUtil {
|
||||
if (right instanceof PsiLambdaExpressionType) {
|
||||
final PsiLambdaExpression rLambdaExpression = ((PsiLambdaExpressionType)right).getExpression();
|
||||
if (left instanceof PsiClassType) {
|
||||
return LambdaUtil.isAcceptable(rLambdaExpression, left);
|
||||
return LambdaUtil.isAcceptable(rLambdaExpression, left, false);
|
||||
}
|
||||
if (left instanceof PsiLambdaExpressionType) {
|
||||
final PsiLambdaExpression lLambdaExpression = ((PsiLambdaExpressionType)left).getExpression();
|
||||
|
||||
+34
-26
@@ -35,8 +35,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
public static final Pair<PsiType,ConstraintType> RAW_INFERENCE = new Pair<PsiType, ConstraintType>(null, ConstraintType.EQUALS);
|
||||
private final PsiManager myManager;
|
||||
|
||||
public PsiResolveHelperImpl(PsiManager manager) {
|
||||
@@ -206,7 +208,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
final Pair<PsiType,ConstraintType> currentSubstitution;
|
||||
if (argumentType instanceof PsiLambdaExpressionType) {
|
||||
currentSubstitution = inferSubstitutionFromLambda(typeParameter, (PsiLambdaExpressionType)argumentType, lowerBound);
|
||||
if (rawType && currentSubstitution == FAILED_INFERENCE || nullPassed && currentSubstitution == null) return new Pair<PsiType, ConstraintType>(null, ConstraintType.EQUALS);
|
||||
if (rawType) {
|
||||
if (currentSubstitution == FAILED_INFERENCE || (currentSubstitution == null && lowerBound == PsiType.NULL)) return RAW_INFERENCE;
|
||||
}
|
||||
if (nullPassed && currentSubstitution == null) return RAW_INFERENCE;
|
||||
} else {
|
||||
currentSubstitution = getSubstitutionForTypeParameterConstraint(typeParameter, parameterType,
|
||||
argumentType, true, PsiUtil.getLanguageLevel(typeParameter));
|
||||
@@ -218,7 +223,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
|
||||
final ConstraintType constraintType = currentSubstitution.getSecond();
|
||||
final PsiType type = currentSubstitution.getFirst();
|
||||
if (type == null) return new Pair<PsiType, ConstraintType>(null, ConstraintType.EQUALS);
|
||||
if (type == null) return RAW_INFERENCE;
|
||||
switch(constraintType) {
|
||||
case EQUALS:
|
||||
if (!(type instanceof PsiWildcardType)) return currentSubstitution;
|
||||
@@ -590,27 +595,31 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
final PsiType functionalInterfaceType,
|
||||
PsiType lowerBound) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (method != null) {
|
||||
final Pair<PsiType, ConstraintType> constraintFromFormalParams = inferConstraintFromLambdaFormalParams(typeParam, resolveResult, method, lambdaExpression);
|
||||
final PsiSubstitutor subst = LambdaUtil.getSubstitutor(method, resolveResult);
|
||||
final Pair<PsiType, ConstraintType> constraintFromFormalParams = inferConstraintFromLambdaFormalParams(typeParam, subst, method, lambdaExpression);
|
||||
if (constraintFromFormalParams != null) return constraintFromFormalParams;
|
||||
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
final PsiSubstitutor subst =
|
||||
TypeConversionUtil.getSuperClassSubstitutor(method.getContainingClass(), resolveResult.getElement(), resolveResult.getSubstitutor());
|
||||
final boolean methodParamsDependOnTypeParams = methodParamsDependOnTypeParams(lambdaExpression, methodParameters, subst, typeParam);
|
||||
if (methodParamsDependOn(typeParam, lambdaExpression, functionalInterfaceType, methodParameters, subst)) {
|
||||
if (lowerBound != PsiType.NULL) {
|
||||
return null;
|
||||
}
|
||||
return getFailedInferenceConstraint(typeParam);
|
||||
}
|
||||
|
||||
final Set<PsiParameterList> lists = LambdaUtil.ourParams.get();
|
||||
if (lists != null && lists.contains(lambdaExpression.getParameterList())){
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiType returnType = subst.substitute(method.getReturnType());
|
||||
if (returnType != null && returnType != PsiType.VOID) {
|
||||
Pair<PsiType, ConstraintType> constraint = null;
|
||||
final List<PsiExpression> expressions = lambdaExpression.getReturnExpressions();
|
||||
for (final PsiExpression expression : expressions) {
|
||||
final boolean independent = LambdaUtil.isFreeFromTypeInferenceArgs(methodParameters, lambdaExpression, expression);
|
||||
if (independent && methodParamsDependOnTypeParams ) {
|
||||
if (lowerBound != PsiType.NULL) {
|
||||
return null;
|
||||
}
|
||||
return FAILED_INFERENCE;
|
||||
}
|
||||
final boolean independent = LambdaUtil.isFreeFromTypeInferenceArgs(methodParameters, lambdaExpression, expression, subst, functionalInterfaceType, typeParam);
|
||||
if (!independent) {
|
||||
if (lowerBound != PsiType.NULL) {
|
||||
return null;
|
||||
@@ -634,7 +643,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
}
|
||||
|
||||
final Pair<PsiType, ConstraintType> returnExprConstraint =
|
||||
getSubstitutionForTypeParameterConstraint(typeParam, returnType, exprType, true, PsiUtil.getLanguageLevel(method));
|
||||
getSubstitutionForTypeParameterConstraint(typeParam, GenericsUtil.eliminateWildcards(returnType), exprType, true, PsiUtil.getLanguageLevel(method));
|
||||
if (returnExprConstraint != null) {
|
||||
if (returnExprConstraint == FAILED_INFERENCE) return returnExprConstraint;
|
||||
if (constraint != null) {
|
||||
@@ -647,17 +656,16 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
}
|
||||
if (constraint != null) return constraint;
|
||||
}
|
||||
if (methodParamsDependOnTypeParams) return getFailedInferenceConstraint(typeParam);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean methodParamsDependOnTypeParams(PsiLambdaExpression lambdaExpression,
|
||||
PsiParameter[] methodParameters,
|
||||
PsiSubstitutor subst,
|
||||
PsiTypeParameter typeParam) {
|
||||
private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiLambdaExpression lambdaExpression,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiParameter[] methodParameters,
|
||||
PsiSubstitutor subst) {
|
||||
for (PsiParameter parameter : methodParameters) {
|
||||
if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), lambdaExpression, typeParam)) {
|
||||
if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, lambdaExpression, typeParam)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -666,7 +674,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
|
||||
@Nullable
|
||||
private static Pair<PsiType, ConstraintType> inferConstraintFromLambdaFormalParams(PsiTypeParameter typeParam,
|
||||
PsiClassType.ClassResolveResult resolveResult,
|
||||
PsiSubstitutor subst,
|
||||
PsiMethod method, PsiLambdaExpression lambdaExpression) {
|
||||
final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters();
|
||||
if (parameters.length == 0) return null;
|
||||
@@ -679,13 +687,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
lambdaArgs[i] = parameter.getType();
|
||||
}
|
||||
|
||||
final PsiSubstitutor subst = resolveResult.getSubstitutor();
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
PsiType[] methodParamTypes = new PsiType[methodParameters.length];
|
||||
for (int i = 0; i < methodParameters.length; i++) {
|
||||
methodParamTypes[i] = subst.substitute(methodParameters[i].getType());
|
||||
}
|
||||
return inferTypeForMethodTypeParameterInner(typeParam, methodParamTypes, lambdaArgs, subst, null, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
return inferTypeForMethodTypeParameterInner(typeParam, methodParamTypes, lambdaArgs, subst, null, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
}
|
||||
|
||||
private static PsiType intersectAllExtends(PsiTypeParameter typeParam, PsiType arg) {
|
||||
@@ -903,8 +910,9 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
if (method == null || methodParamsDependOnTypeParams((PsiLambdaExpression)expression, method.getParameterList().getParameters(),
|
||||
TypeConversionUtil.getSuperClassSubstitutor(method.getContainingClass(), resolveResult.getElement(), resolveResult.getSubstitutor()), typeParameter)) {
|
||||
if (method == null || methodParamsDependOn(typeParameter, (PsiLambdaExpression)expression,
|
||||
functionalInterfaceType, method.getParameterList().getParameters(),
|
||||
LambdaUtil.getSubstitutor(method, resolveResult))) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
final PsiParameter param = i < methodParameters.length ? methodParameters[i] : methodParameters[methodParameters.length - 1];
|
||||
final PsiType paramType = param.getType();
|
||||
if (!LambdaUtil.isAcceptable(lambdaExpression, paramType)) {
|
||||
if (!LambdaUtil.isAcceptable(lambdaExpression, conflict.getSubstitutor().substitute(paramType), true)) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
/*todo
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
*/
|
||||
import java.util.*;
|
||||
|
||||
class LambdaTest<TT> {
|
||||
interface BinaryOperator<T> {
|
||||
|
||||
public T eval(T left, T right);
|
||||
}
|
||||
|
||||
interface Mapper<T, U> {
|
||||
U map(T t);
|
||||
}
|
||||
|
||||
public static <T, U> LambdaTest<U> map(final Iterable<? extends T> iterable, final Mapper<? super T, ? extends U> mapper) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TT reduce(TT base, BinaryOperator<TT> reducer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void test() {
|
||||
final List<String> aStrings = Arrays.asList("1", "2", "3");
|
||||
map(aStrings, s -> s.length()).reduce(0, (l, r) -> l + r);
|
||||
}
|
||||
}
|
||||
|
||||
class LambdaTest2<TypeParam> {
|
||||
interface BinaryOperator<T> {
|
||||
public T eval(T left, T right);
|
||||
}
|
||||
|
||||
interface Mapper<T, U> {
|
||||
U map(T t);
|
||||
}
|
||||
|
||||
public <U> LambdaTest<U> map(final Mapper<? super TypeParam, ? extends U> mapper) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeParam reduce(TypeParam base, BinaryOperator<TypeParam> reducer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void test() {
|
||||
final LambdaTest2<String> lt = new LambdaTest2<>();
|
||||
lt.map(s -> s.length()).reduce(0, (l, r) -> l + r);
|
||||
}
|
||||
}
|
||||
+24
@@ -34,3 +34,27 @@ class Test3 {
|
||||
bar(<error descr="Cyclic inference">x->{}</error>, new ArrayList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Test4 {
|
||||
protected <T, U> U exerciseOps(TestData<T> data, TerminalOp1<T, U> terminal, IntermediateOp1... ops) {
|
||||
return exerciseOps(data, (u, v) -> u.equals(v), terminal, ops);
|
||||
}
|
||||
|
||||
protected static <T, U> U exerciseOps(TestData<T> data,
|
||||
BiPredicate1<U, U> equalator,
|
||||
TerminalOp1<T, U> terminalOp,
|
||||
IntermediateOp1[] ops) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface IntermediateOp1<T,U> {
|
||||
|
||||
}
|
||||
public interface BiPredicate1<T, U> extends IntermediateOp1<T, U>{
|
||||
boolean _(T t, U u);
|
||||
}
|
||||
|
||||
public interface TerminalOp1<T, U> extends IntermediateOp1<T, U> {}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -125,6 +125,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIncompleteSubst() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class InferLambdaParameterTypeIntention extends Intention {
|
||||
if (parameters.length != lambdaParameters.length) return null;
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
final PsiType psiType = GenericsUtil.eliminateWildcards(resolveResult.getSubstitutor().substitute(parameter.getType()));
|
||||
final PsiType psiType = GenericsUtil.eliminateWildcards(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult).substitute(parameter.getType()));
|
||||
if (psiType != null) {
|
||||
buf.append(psiType.getPresentableText()).append(" ").append(lambdaParameters[i].getName());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user