java 8: intersection type casts (IDEA-98843)

This commit is contained in:
anna
2013-01-11 15:59:40 +01:00
parent d919ca79a3
commit 6f2878cdf7
8 changed files with 68 additions and 18 deletions

View File

@@ -116,6 +116,12 @@ public class LambdaUtil {
}
public static boolean isAcceptable(PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) {
if (leftType instanceof PsiIntersectionType) {
for (PsiType conjunctType : ((PsiIntersectionType)leftType).getConjuncts()) {
if (isAcceptable(lambdaExpression, conjunctType, checkReturnType)) return true;
}
return false;
}
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(leftType);
final PsiClass psiClass = resolveResult.getElement();
if (psiClass instanceof PsiAnonymousClass) {
@@ -462,17 +468,16 @@ public class LambdaUtil {
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);
}
}
if (type instanceof PsiIntersectionType) {
final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
for (PsiType conjunct : conjuncts) {
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
if (lambdaParameterFromType != null) return lambdaParameterFromType;
}
} else {
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
if (lambdaParameterFromType != null) {
return lambdaParameterFromType;
}
}
}
@@ -485,6 +490,23 @@ public class LambdaUtil {
return new PsiLambdaParameterType(param);
}
private static PsiType getLambdaParameterFromType(int parameterIndex, PsiLambdaExpression lambdaExpression, PsiType conjunct) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(conjunct);
if (resolveResult != null) {
final PsiMethod method = getFunctionalInterfaceMethod(conjunct);
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, conjunct, lambdaExpression, null)) {
return GenericsUtil.eliminateWildcards(psiType);
}
}
}
}
return null;
}
public static PsiSubstitutor inferFromReturnType(final PsiTypeParameter[] typeParameters,
final PsiType returnType,
@Nullable final PsiType interfaceMethodReturnType,

View File

@@ -116,6 +116,12 @@ public class PsiMethodReferenceUtil {
public static boolean isAcceptable(@Nullable final PsiMethodReferenceExpression methodReferenceExpression, PsiType left) {
if (methodReferenceExpression == null) return false;
if (left instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType)left).getConjuncts()) {
if (isAcceptable(methodReferenceExpression, conjunct)) return true;
}
return false;
}
Map<PsiMethodReferenceExpression, PsiType> map = ourRefs.get();
if (map == null) {
map = new HashMap<PsiMethodReferenceExpression, PsiType>();

View File

@@ -667,9 +667,7 @@ public class TypeConversionUtil {
if (right instanceof PsiMethodReferenceType) {
final PsiMethodReferenceExpression methodReferenceExpression = ((PsiMethodReferenceType)right).getExpression();
if (left instanceof PsiClassType) {
return PsiMethodReferenceUtil.isAcceptable(methodReferenceExpression, (PsiClassType)left);
} else if (left instanceof PsiLambdaExpressionType) {
if (left instanceof PsiLambdaExpressionType) {
final PsiType rType = methodReferenceExpression.getFunctionalInterfaceType();
final PsiType lType = ((PsiLambdaExpressionType)left).getExpression().getFunctionalInterfaceType();
return Comparing.equal(rType, lType);
@@ -678,18 +676,17 @@ public class TypeConversionUtil {
final PsiType lType = ((PsiMethodReferenceType)left).getExpression().getFunctionalInterfaceType();
return Comparing.equal(rType, lType);
}
return PsiMethodReferenceUtil.isAcceptable(methodReferenceExpression, left);
}
if (right instanceof PsiLambdaExpressionType) {
final PsiLambdaExpression rLambdaExpression = ((PsiLambdaExpressionType)right).getExpression();
if (left instanceof PsiClassType) {
return LambdaUtil.isAcceptable(rLambdaExpression, left, false);
}
if (left instanceof PsiLambdaExpressionType) {
final PsiLambdaExpression lLambdaExpression = ((PsiLambdaExpressionType)left).getExpression();
final PsiType rType = rLambdaExpression.getFunctionalInterfaceType();
final PsiType lType = lLambdaExpression.getFunctionalInterfaceType();
return Comparing.equal(rType, lType);
}
return LambdaUtil.isAcceptable(rLambdaExpression, left, false);
}
if (left instanceof PsiIntersectionType) {

View File

@@ -105,11 +105,14 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
cachedType = componentType.createArrayType();
}
else {
final PsiElement opElement = PsiTreeUtil.skipSiblingsForward(element.getPsi(), PsiWhiteSpace.class);
final List<PsiTypeElement> typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class);
final List<PsiType> types = ContainerUtil.map(typeElements, new Function<PsiTypeElement, PsiType>() {
@Override public PsiType fun(final PsiTypeElement psiTypeElement) { return psiTypeElement.getType(); }
});
cachedType = new PsiDisjunctionType(types, getManager());
cachedType = opElement instanceof PsiJavaToken && ((PsiJavaToken)opElement).getTokenType() == JavaTokenType.AND
? PsiIntersectionType.createIntersection(types.toArray(new PsiType[types.size()]))
: new PsiDisjunctionType(types, getManager());
}
}
else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) {

View File

@@ -0,0 +1,8 @@
import java.io.Serializable;
import java.util.*;
class Test {
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> foo() {
return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
}

View File

@@ -0,0 +1,6 @@
import java.io.Serializable;
class Test {
{
Runnable r = (Runnable & Serializable)Test::new;
}
}

View File

@@ -177,6 +177,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIntersectionTypeInCast() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}

View File

@@ -153,6 +153,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest(true);
}
public void testIntersectionTypeInCast() throws Exception {
doTest(false);
}
private void doTest() throws Exception {
doTest(false);
}