conditional expression type: check poly expression first (IDEA-148965)

This commit is contained in:
Anna Kozlova
2015-12-07 18:47:41 +01:00
parent 558d364281
commit a15905ae13
6 changed files with 64 additions and 12 deletions

View File

@@ -178,8 +178,12 @@ public class PsiPolyExpressionUtil {
type = method.getReturnType();
}
}
if (TypeConversionUtil.isNumericType(type)) return ConditionalKind.NUMERIC;
if (TypeConversionUtil.isBooleanType(type)) return ConditionalKind.BOOLEAN;
final ConditionalKind kind = isBooleanOrNumericType(type);
if (kind != null) {
return kind;
}
if (expr instanceof PsiConditionalExpression) {
final PsiExpression thenExpression = ((PsiConditionalExpression)expr).getThenExpression();
final PsiExpression elseExpression = ((PsiConditionalExpression)expr).getElseExpression();
@@ -190,4 +194,21 @@ public class PsiPolyExpressionUtil {
}
return null;
}
@Nullable
private static ConditionalKind isBooleanOrNumericType(PsiType type) {
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type);
if (TypeConversionUtil.isNumericType(type)) return ConditionalKind.NUMERIC;
if (TypeConversionUtil.isBooleanType(type)) return ConditionalKind.BOOLEAN;
if (psiClass instanceof PsiTypeParameter) {
for (PsiClassType classType : psiClass.getExtendsListTypes()) {
final ConditionalKind kind = isBooleanOrNumericType(classType);
if (kind != null) {
return kind;
}
}
}
return null;
}
}

View File

@@ -65,6 +65,15 @@ public class PsiConditionalExpressionImpl extends ExpressionPsiElement implement
if (type2 == null) return type1;
if (type1.equals(type2)) return type1;
if (PsiUtil.isLanguageLevel8OrHigher(this) &&
PsiPolyExpressionUtil.isPolyExpression(this) &&
!MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(this.getParent()))) {
//15.25.3 Reference Conditional Expressions
// The type of a poly reference conditional expression is the same as its target type.
return InferenceSession.getTargetType(this);
}
final int typeRank1 = TypeConversionUtil.getTypeRank(type1);
final int typeRank2 = TypeConversionUtil.getTypeRank(type2);
@@ -90,14 +99,6 @@ public class PsiConditionalExpressionImpl extends ExpressionPsiElement implement
if (TypeConversionUtil.isNullType(type1) && !(type2 instanceof PsiPrimitiveType)) return type2;
if (TypeConversionUtil.isNullType(type2) && !(type1 instanceof PsiPrimitiveType)) return type1;
if (PsiUtil.isLanguageLevel8OrHigher(this) &&
PsiPolyExpressionUtil.isPolyExpression(this) &&
!MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(this.getParent()))) {
//15.25.3 Reference Conditional Expressions
// The type of a poly reference conditional expression is the same as its target type.
return InferenceSession.getTargetType(this);
}
if (TypeConversionUtil.isAssignable(type1, type2, false)) return type1;
if (TypeConversionUtil.isAssignable(type2, type1, false)) return type2;
if (!PsiUtil.isLanguageLevel5OrHigher(this)) {

View File

@@ -0,0 +1,26 @@
class Conditional {
void m(Object p, boolean b) {
int a = b ? <error descr="Incompatible types. Found: 'null', required: 'int'">null</error> : ((Getter<Integer>) p).get();
int a1 = b ? <error descr="Incompatible types. Found: 'null', required: 'int'">null</error> : Conditional.<Integer>f();
int a2 = b ? null : 1;
int a3 = b ? null : f1();
int a4 = b ? null : f2();
}
private static <T> T f() {
return null;
}
private static int f1() {
return 1;
}
private static <T extends Integer, S extends T> S f2() {
return null;
}
}
interface Getter<A> {
A get();
}

View File

@@ -1,7 +1,7 @@
// "Cast to 'B'" "true"
class A {
void f(B b) {
B s = <caret>b == null ? null : (B) this;
B s =b == null ? null : <caret>(B) this;
}
}
class B extends A {}

View File

@@ -1,7 +1,7 @@
// "Cast to 'B'" "true"
class A {
void f(B b) {
B s = <caret>b == null ? null : this;
B s =b == null ? null : <caret>this;
}
}
class B extends A {}

View File

@@ -343,6 +343,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void testPolyConditionalExpressionWithTargetPrimitive() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(false);
}