lambda: intersection type produces conjunction of abstract methods

This commit is contained in:
Anna Kozlova
2014-04-17 11:58:15 +02:00
parent bd9dbfc7d5
commit 552dfe92a9
4 changed files with 48 additions and 8 deletions

View File

@@ -97,8 +97,17 @@ public class LambdaHighlightingUtil {
@Nullable
public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
if (functionalInterfaceType instanceof PsiIntersectionType) {
for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
if (checkInterfaceFunctional(type) == null) return null;
if (!LambdaUtil.isFunctionalType(functionalInterfaceType)) {
int count = 0;
for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
if (checkInterfaceFunctional(type) == null) {
count++;
}
}
if (count > 1) {
return "Multiple non-overriding abstract methods found in " + functionalInterfaceType.getPresentableText();
}
}
}
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);

View File

@@ -103,9 +103,7 @@ public class LambdaUtil {
public static boolean isFunctionalType(PsiType type) {
if (type instanceof PsiIntersectionType) {
for (PsiType type1 : ((PsiIntersectionType)type).getConjuncts()) {
if (isFunctionalType(type1)) return true;
}
return extractFunctionalConjunct((PsiIntersectionType)type) != null;
}
return isFunctionalClass(PsiUtil.resolveGenericsClassInType(type).getElement());
}
@@ -286,9 +284,8 @@ public class LambdaUtil {
} else if (parent instanceof PsiTypeCastExpression) {
final PsiType castType = ((PsiTypeCastExpression)parent).getType();
if (castType instanceof PsiIntersectionType) {
for (PsiType conjunctType : ((PsiIntersectionType)castType).getConjuncts()) {
if (getFunctionalInterfaceMethod(conjunctType) != null) return conjunctType;
}
final PsiType conjunct = extractFunctionalConjunct((PsiIntersectionType)castType);
if (conjunct != null) return conjunct;
}
return castType;
}
@@ -363,6 +360,19 @@ public class LambdaUtil {
return null;
}
@Nullable
private static PsiType extractFunctionalConjunct(PsiIntersectionType type) {
PsiType conjunct = null;
for (PsiType conjunctType : ((PsiIntersectionType)type).getConjuncts()) {
final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(conjunctType);
if (interfaceMethod != null) {
if (conjunct != null && !conjunct.equals(conjunctType)) return null;
conjunct = conjunctType;
}
}
return conjunct;
}
private static PsiType getFunctionalInterfaceTypeByContainingLambda(@NotNull PsiLambdaExpression parentLambda) {
final PsiType parentInterfaceType = parentLambda.getFunctionalInterfaceType();
return parentInterfaceType != null ? getFunctionalInterfaceReturnType(parentInterfaceType) : null;

View File

@@ -0,0 +1,20 @@
import java.io.Serializable;
class Test {
interface I {
void foo();
}
interface A {
void bar(int i);
}
{
Object o1 = (Serializable & I) () -> {};
Object o2 = (I & Serializable) () -> {};
Object o3 = (I & Runnable) <error descr="Multiple non-overriding abstract methods found in Runnable & I">() -> {}</error>;
Object o4 = (A & Runnable) <error descr="Multiple non-overriding abstract methods found in Runnable & A">() -> {}</error>;
Object o5 = (Runnable & A) <error descr="Multiple non-overriding abstract methods found in Runnable & A">() -> {}</error>;
}
}

View File

@@ -101,6 +101,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testBreakContinueInside() {doTest();}
public void testSameLambdaParamNames() {doTest();}
public void testIDEA123308() {doTest();}
public void testIntersection() {doTest();}
private void doTest() {
doTest(false);