inference: treat only non-proper bounds of inference variables as unchecked conversion (IDEA-204125)

This commit is contained in:
Anna.Kozlova
2019-01-22 13:45:03 +01:00
parent 4c48f0c2b0
commit 41042d7f09
6 changed files with 57 additions and 14 deletions
@@ -310,7 +310,7 @@ public class InferenceIncorporationPhase {
for (PsiType eqBound : eqBounds) {
if (eqBound == null || PsiType.NULL.equals(eqBound) || eqBound instanceof PsiWildcardType) continue;
if (Registry.is("javac.unchecked.subtyping.during.incorporation", true)) {
if (TypeCompatibilityConstraint.isUncheckedConversion(upperBound, eqBound)) {
if (TypeCompatibilityConstraint.isUncheckedConversion(upperBound, eqBound, mySession)) {
if (PsiUtil.resolveClassInType(eqBound) instanceof PsiTypeParameter && !mySession.isProperType(upperBound)) {
mySession.setErased();
}
@@ -319,7 +319,7 @@ public class InferenceIncorporationPhase {
if (!mySession.isProperType(upperBound) &&
eqBound instanceof PsiCapturedWildcardType &&
TypeCompatibilityConstraint.isUncheckedConversion(upperBound, ((PsiCapturedWildcardType)eqBound).getUpperBound())) {
TypeCompatibilityConstraint.isUncheckedConversion(upperBound, ((PsiCapturedWildcardType)eqBound).getUpperBound(), mySession)) {
mySession.setErased();
continue;
}
@@ -739,7 +739,7 @@ public class InferenceSession {
return inferenceVariable;
}
if (targetType instanceof PsiClassType) {
if (hasUncheckedBounds(inferenceVariable, (PsiClassType)targetType) ||
if (hasUncheckedBounds(inferenceVariable, (PsiClassType)targetType, this) ||
hasWildcardParameterization(inferenceVariable, (PsiClassType)targetType)) {
return inferenceVariable;
}
@@ -761,13 +761,15 @@ public class InferenceSession {
return false;
}
private static boolean hasUncheckedBounds(InferenceVariable inferenceVariable, PsiClassType targetType) {
private static boolean hasUncheckedBounds(InferenceVariable inferenceVariable,
PsiClassType targetType,
InferenceSession session) {
if (!targetType.isRaw()) {
final InferenceBound[] boundTypes = {InferenceBound.EQ, InferenceBound.LOWER};
for (InferenceBound inferenceBound : boundTypes) {
final List<PsiType> bounds = inferenceVariable.getBounds(inferenceBound);
for (PsiType bound : bounds) {
if (TypeCompatibilityConstraint.isUncheckedConversion(targetType, bound)) {
if (TypeCompatibilityConstraint.isUncheckedConversion(targetType, bound, session)) {
return true;
}
}
@@ -37,7 +37,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
final PsiType type = myExpression.getType();
session.registerIncompatibleErrorMessage((type != null ? type.getPresentableText() : myExpression.getText()) + " is not compatible with " + session.getPresentableText(myT));
}
else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType) && !JavaGenericsUtil.isReifiableType(myT)) {
else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType, session) && !JavaGenericsUtil.isReifiableType(myT)) {
session.setErased();
}
return assignmentCompatible;
@@ -16,8 +16,10 @@
package com.intellij.psi.impl.source.resolve.graphInference.constraints;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceBound;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
@@ -57,7 +59,7 @@ public class TypeCompatibilityConstraint implements ConstraintFormula {
}
}
if (isUncheckedConversion(myT, myS)) {
if (isUncheckedConversion(myT, myS, session)) {
session.setErased();
return true;
}
@@ -66,28 +68,32 @@ public class TypeCompatibilityConstraint implements ConstraintFormula {
return true;
}
public static boolean isUncheckedConversion(final PsiType t, final PsiType s) {
public static boolean isUncheckedConversion(final PsiType t,
final PsiType s,
InferenceSession session) {
if (t instanceof PsiClassType && !((PsiClassType)t).isRaw()) {
final PsiClassType.ClassResolveResult tResult = ((PsiClassType)t).resolveGenerics();
final PsiClass tClass = tResult.getElement();
if (s instanceof PsiClassType && isUncheckedConversion(tClass, (PsiClassType)s)) {
if (s instanceof PsiClassType && isUncheckedConversion(tClass, (PsiClassType)s, session)) {
return true;
}
else if (s instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType)s).getConjuncts()) {
if (conjunct instanceof PsiClassType && isUncheckedConversion(tClass, (PsiClassType)conjunct)) {
if (conjunct instanceof PsiClassType && isUncheckedConversion(tClass, (PsiClassType)conjunct, session)) {
return true;
}
}
}
}
else if (t instanceof PsiArrayType && s != null && t.getArrayDimensions() == s.getArrayDimensions()) {
return isUncheckedConversion(t.getDeepComponentType(), s.getDeepComponentType());
return isUncheckedConversion(t.getDeepComponentType(), s.getDeepComponentType(), session);
}
return false;
}
private static boolean isUncheckedConversion(PsiClass tClass, PsiClassType s) {
private static boolean isUncheckedConversion(PsiClass tClass,
PsiClassType s,
InferenceSession session) {
final PsiClassType.ClassResolveResult sResult = s.resolveGenerics();
final PsiClass sClass = sResult.getElement();
if (tClass != null && sClass != null && !(sClass instanceof InferenceVariable)) {
@@ -97,8 +103,15 @@ public class TypeCompatibilityConstraint implements ConstraintFormula {
return true;
}
}
else if (tClass instanceof InferenceVariable && s.isRaw() && tClass.isInheritor(sClass, true)) {
return true;
else if (tClass instanceof InferenceVariable && s.isRaw()) {
for (PsiType bound : ((InferenceVariable)tClass).getBounds(InferenceBound.UPPER)) {
if (!session.isProperType(bound)) {
PsiClass boundClass = PsiUtil.resolveClassInClassTypeOnly(bound);
if (boundClass != null && InheritanceUtil.isInheritorOrSelf(boundClass, sClass, true)) {
return true;
}
}
}
}
}
return false;
@@ -0,0 +1,27 @@
class Test_3 {
public static void main(String[] aArgs) {
Info info = null;
update(info)
.withSuper()
.withChild();
}
public interface Info<_Info> { }
public static <Type extends Info<?>> C<?> update(Type aType) {
return null;
}
public static class C<_Builder extends C< _Builder>> extends A<_Builder> {
public _Builder withChild() {
return null;
}
}
public static class A<_B extends A<_B>> {
public _B withSuper() {
return null;
}
}
}
@@ -1043,4 +1043,5 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testNestedWildcardsWithImplicitBounds() { doTest(); }
public void testCallOnRawWithExplicitTypeArguments() { doTest(); }
public void testNoCaptureConversionDuringDetectingSupertypesDeepInHierarchy() { doTest(); }
public void testIgnoreErasureForProperTypeBound() { doTest(); }
}