poly conditional expression type = target type (IDEA-122401)

This commit is contained in:
Anna Kozlova
2014-03-19 19:08:54 +01:00
parent 01fc6fe439
commit e6547e3991
9 changed files with 74 additions and 14 deletions

View File

@@ -37,6 +37,7 @@ import com.intellij.psi.*;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTagValue;
@@ -1460,4 +1461,25 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
return false;
}
}
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
super.visitConditionalExpression(expression);
if (PsiUtil.isLanguageLevel8OrHigher(expression) && PsiPolyExpressionUtil.isPolyExpression(expression)) {
final PsiExpression thenExpression = expression.getThenExpression();
final PsiExpression elseExpression = expression.getElseExpression();
if (thenExpression != null && elseExpression != null) {
final PsiType conditionalType = expression.getType();
if (conditionalType != null) {
final PsiExpression[] sides = new PsiExpression[] {thenExpression, elseExpression};
for (PsiExpression side : sides) {
final PsiType sideType = side.getType();
if (sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) {
myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side));
}
}
}
}
}
}
}

View File

@@ -346,10 +346,7 @@ public class InferenceSession {
if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method)) {
PsiType returnType = method.getReturnType();
if (!PsiType.VOID.equals(returnType) && returnType != null) {
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context);
if (targetType == null) {
targetType = getTargetType(context);
}
PsiType targetType = getTargetType(context);
if (targetType != null) {
registerConstraints(PsiUtil.isRawSubstitutor(method, mySiteSubstitutor) ? returnType : mySiteSubstitutor.substitute(returnType), targetType);
}
@@ -465,7 +462,11 @@ public class InferenceSession {
return false;
}
private static PsiType getTargetType(final PsiExpression context) {
public static PsiType getTargetType(final PsiExpression context) {
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context);
if (targetType != null) {
return targetType;
}
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent());
if (parent instanceof PsiExpressionList) {
PsiElement gParent = parent.getParent();
@@ -495,11 +496,7 @@ public class InferenceSession {
}
}
} else if (parent instanceof PsiConditionalExpression) {
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent);
if (targetType == null) {
targetType = getTargetType((PsiExpression)parent);
}
return targetType;
return getTargetType((PsiExpression)parent);
}
else if (parent instanceof PsiLambdaExpression) {
if (PsiUtil.skipParenthesizedExprUp(parent.getParent()) instanceof PsiExpressionList) {

View File

@@ -18,9 +18,12 @@ package com.intellij.psi.impl.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -83,6 +86,14 @@ 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(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 @@
import java.util.Comparator;
class NullComparator<T> {
private final Comparator<T> real = null;
private Comparator<? super T> other;
private Comparator<T> another;
NullComparator(Comparator<? super T> real) {
}
public NullComparator<T> thenComparing() {
return new NullComparator<>(real == null ? other : another);
}
Comparator<T> a() {
return null;
}
Comparator<? super T> b() {
return null;
}
public NullComparator<T> thenComparing1() {
return new NullComparator<>(real == null ? a() : b());
}
}

View File

@@ -7,6 +7,6 @@ interface B {}
}
void bar (boolean a, A a1, B b1){
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'T'">T t = a ? a1 : b1;</error>
T t = a ? <error descr="Incompatible types. Found: 'A', required: 'T'">a1</error> : <error descr="Incompatible types. Found: 'B', required: 'T'">b1</error>;
}
}

View File

@@ -12,7 +12,7 @@ class MS {
void test(boolean cond) {
m(cond ? () -> 26 : () -> 24);
m<error descr="Ambiguous method call: both 'MS.m(GetInt)' and 'MS.m(GetInteger)' match">(cond ? () -> 26 : () -> new Integer(42))</error>;
m<error descr="Cannot resolve method 'm(?)'">(cond ? () -> 26 : () -> new Integer(42))</error>;
m(cond ? () -> new Integer(26) : () -> new Integer(42));
}
}

View File

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

View File

@@ -743,6 +743,10 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA122401() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}