lambda/method refs: more specific according to 15.12.2.5 - prefer private when private type is given/reference when reference type is given

This commit is contained in:
anna
2013-02-27 18:03:32 +01:00
parent 47c7983713
commit a55b0fa17b
3 changed files with 80 additions and 9 deletions
@@ -652,7 +652,7 @@ public class LambdaUtil {
final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict);
if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType || actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) {
if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) {
int moreSpecific1 = isMoreSpecific(interfaceReturnType, interfaceReturnType1);
int moreSpecific1 = isMoreSpecific(interfaceReturnType, interfaceReturnType1, actualParameterTypes[functionalInterfaceIdx]);
if (moreSpecific < 0 && moreSpecific1 > 0 || moreSpecific > 0 && moreSpecific1 < 0) {
moreSpecific = 0;
break;
@@ -676,17 +676,33 @@ public class LambdaUtil {
}
}
private static int isMoreSpecific(PsiType returnType, PsiType returnType1) {
enum TypeKind {
PRIMITIVE, REFERENCE, NONE_DETERMINED
}
private static int isMoreSpecific(PsiType returnType, PsiType returnType1, PsiType lambdaType) {
if (returnType == PsiType.VOID || returnType1 == PsiType.VOID) return 0;
if (returnType instanceof PsiPrimitiveType) {
if (!(returnType1 instanceof PsiPrimitiveType)) {
return -1;
} else {
return TypeConversionUtil.isAssignable(returnType, returnType1) ? 1 : -1;
TypeKind typeKind = TypeKind.PRIMITIVE;
if (lambdaType instanceof PsiLambdaExpressionType) {
typeKind = areLambdaReturnExpressionsPrimitive((PsiLambdaExpressionType)lambdaType);
} else if (lambdaType instanceof PsiMethodReferenceType) {
final PsiElement referencedElement = ((PsiMethodReferenceType)lambdaType).getExpression().resolve();
if (referencedElement instanceof PsiMethod && !(((PsiMethod)referencedElement).getReturnType() instanceof PsiPrimitiveType)) {
typeKind = TypeKind.REFERENCE;
}
}
if (returnType1 instanceof PsiPrimitiveType) {
return 1;
if (typeKind != TypeKind.NONE_DETERMINED) {
if (returnType instanceof PsiPrimitiveType) {
final int moreSpecific = typeKind == TypeKind.PRIMITIVE ? 1 : -1;
if (!(returnType1 instanceof PsiPrimitiveType)) {
return -moreSpecific;
} else {
return TypeConversionUtil.isAssignable(returnType, returnType1) ? moreSpecific : -moreSpecific;
}
}
if (returnType1 instanceof PsiPrimitiveType) {
return typeKind == TypeKind.PRIMITIVE ? 1 : -1;
}
}
final PsiClassType.ClassResolveResult r = PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(returnType));
@@ -728,6 +744,28 @@ public class LambdaUtil {
return 0;
}
private static TypeKind areLambdaReturnExpressionsPrimitive(PsiLambdaExpressionType lambdaType) {
final List<PsiExpression> returnExpressions = getReturnExpressions(lambdaType.getExpression());
TypeKind typeKind = TypeKind.NONE_DETERMINED;
for (PsiExpression expression : returnExpressions) {
final PsiType returnExprType = expression.getType();
if (returnExprType instanceof PsiPrimitiveType) {
if (typeKind == TypeKind.REFERENCE) {
typeKind = TypeKind.NONE_DETERMINED;
break;
}
typeKind = TypeKind.PRIMITIVE;
} else {
if (typeKind == TypeKind.PRIMITIVE) {
typeKind = TypeKind.NONE_DETERMINED;
break;
}
typeKind = TypeKind.REFERENCE;
}
}
return typeKind;
}
@Nullable
private static PsiType getReturnType(int functionalTypeIdx, CandidateInfo method) {
final PsiParameter[] methodParameters = ((PsiMethod)method.getElement()).getParameterList().getParameters();
@@ -0,0 +1,29 @@
class Test {
static class Inner {
int foo() { return 0; }
Integer fooBoxed() { return 0; }
}
void test(Stream<Inner> sp) {
IntStream mi = sp.map(Inner::foo);
Stream<Integer> mI = sp.map(Inner::fooBoxed);
IntStream li = sp.map(inner->inner.foo());
Stream<Integer> lI = sp.map(inner -> inner.fooBoxed());
}
interface Stream<T> {
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream map(IntFunction<? super T> mapper);
}
interface Function<T, R> {
public R _(T t);
}
interface IntFunction<T> {
public int _(T t);
}
interface IntStream {}
}
@@ -216,6 +216,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest(true);
}
public void testAmbiguityReturnValueResolution3() throws Exception {
doTest();
}
public void testLambdaOnVarargsPlace1() throws Exception {
doTest();
}