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:
Anna Kozlova
2012-09-06 13:07:11 +04:00
parent 771d928deb
commit d474aa3f1c
11 changed files with 230 additions and 85 deletions
@@ -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();
@@ -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);
}
}
@@ -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
@@ -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);
}
}
@@ -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> {}
}
@@ -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);
}
@@ -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());
}