treat type parameter array upper bounds (IDEA-190380)

This commit is contained in:
Anna.Kozlova
2018-04-17 18:23:41 +02:00
parent d781e8e167
commit 42d204757e
7 changed files with 39 additions and 24 deletions
@@ -60,6 +60,8 @@ public class TypeConversionUtil {
}
};
private static final Key<PsiElement> ORIGINAL_CONTEXT = Key.create("ORIGINAL_CONTEXT");
public static final Key<PsiType> LOWER_BOUND = Key.create("LowBound");
public static final Key<PsiType> UPPER_BOUND = Key.create("UpperBound");
static {
TYPE_TO_RANK_MAP.put(PsiType.BYTE, BYTE_RANK);
@@ -808,7 +810,16 @@ public class TypeConversionUtil {
return isAssignable(left, ((PsiDisjunctionType)right).getLeastUpperBound(), allowUncheckedConversion, capture);
}
if (left instanceof PsiArrayType) return false;
if (left instanceof PsiArrayType) {
if (right instanceof PsiClassType) {
PsiClass aClass = ((PsiClassType)right).resolve();
if (aClass instanceof PsiTypeParameter) {
PsiType upperBound = getUpperBound(aClass);
return upperBound != null && isAssignable(left, upperBound, allowUncheckedConversion, capture);
}
}
return false;
}
if (right instanceof PsiPrimitiveType) {
if (isVoidType(right)) return false;
if (!(left instanceof PsiPrimitiveType)) {
@@ -1450,6 +1461,14 @@ public class TypeConversionUtil {
parameter.putUserData(ORIGINAL_CONTEXT, context);
}
public static PsiType getUpperBound(@NotNull PsiClass psiClass) {
return psiClass.getUserData(UPPER_BOUND);
}
public static PsiType getLowerBound(@NotNull PsiClass psiClass) {
return psiClass.getUserData(LOWER_BOUND);
}
private interface Caster {
@NotNull
Object cast(@NotNull Object operand);
@@ -19,14 +19,10 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
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.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.JavaClassSupers;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.util.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,7 +49,7 @@ public class JavaClassSupersImpl extends JavaClassSupers {
bounds = ((InferenceVariable)superClass).getBounds(InferenceBound.LOWER);
}
else if (superClass instanceof PsiTypeParameter) {
final PsiType lowerBound = InferenceSession.getLowerBound(superClass);
final PsiType lowerBound = TypeConversionUtil.getLowerBound(superClass);
if (lowerBound != null) {
bounds = Collections.singletonList(lowerBound);
}
@@ -28,7 +28,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.PsiClassReferenceListStub;
import com.intellij.psi.impl.source.ClassInnerStuffCache;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.ElementClassFilter;
import com.intellij.psi.scope.ElementClassHint;
@@ -998,7 +997,7 @@ public class PsiClassImplUtil {
if (psiClass.isAnnotationType()) {
return new PsiClassType[]{getAnnotationSuperType(psiClass, JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory())};
}
PsiType upperBound = InferenceSession.getUpperBound(psiClass);
PsiType upperBound = TypeConversionUtil.getUpperBound(psiClass);
if (upperBound == null && psiClass instanceof PsiTypeParameter) {
upperBound = LambdaUtil.getFunctionalTypeMap().get(psiClass);
}
@@ -1041,7 +1040,7 @@ public class PsiClassImplUtil {
if (psiClass.isAnnotationType()) {
return CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION.equals(baseClass.getQualifiedName());
}
PsiType upperBound = InferenceSession.getUpperBound(psiClass);
PsiType upperBound = TypeConversionUtil.getUpperBound(psiClass);
if (upperBound == null && psiClass instanceof PsiTypeParameter) {
upperBound = LambdaUtil.getFunctionalTypeMap().get(psiClass);
}
@@ -42,8 +42,6 @@ import java.util.*;
public class InferenceSession {
private static final Logger LOG = Logger.getInstance(InferenceSession.class);
private static final Key<PsiType> LOWER_BOUND = Key.create("LowBound");
private static final Key<PsiType> UPPER_BOUND = Key.create("UpperBound");
private static final Key<Boolean> ERASED = Key.create("UNCHECKED_CONVERSION");
private static final Function<Pair<PsiType, PsiType>, PsiType> UPPER_BOUND_FUNCTION = pair -> GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
@@ -133,18 +131,11 @@ public class InferenceSession {
initBounds(typeParams);
}
public static PsiType getUpperBound(@NotNull PsiClass psiClass) {
return psiClass.getUserData(UPPER_BOUND);
}
public static PsiType getLowerBound(@NotNull PsiClass psiClass) {
return psiClass.getUserData(LOWER_BOUND);
}
public static PsiType createTypeParameterTypeWithUpperBound(PsiType upperBound, PsiElement place) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(place.getProject());
final PsiTypeParameter parameter = elementFactory.createTypeParameterFromText("T", place);
parameter.putUserData(UPPER_BOUND, upperBound);
parameter.putUserData(TypeConversionUtil.UPPER_BOUND, upperBound);
return elementFactory.createType(parameter);
}
@@ -1139,9 +1130,9 @@ public class InferenceSession {
return false;
}
}
parameter.putUserData(LOWER_BOUND, lub);
parameter.putUserData(TypeConversionUtil.LOWER_BOUND, lub);
}
parameter.putUserData(UPPER_BOUND,
parameter.putUserData(TypeConversionUtil.UPPER_BOUND,
composeBound(var, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(substitutor), true));
TypeConversionUtil.markAsFreshVariable(parameter, myContext);
if (!var.addBound(elementFactory.createType(parameter), InferenceBound.EQ, myIncorporationPhase)) {
@@ -1195,7 +1186,7 @@ public class InferenceSession {
//restore captured wildcard from method return type when no additional constraints were inferred
//to preserve equality of type arguments
if (capturedWildcard != null &&
capturedWildcard.getUpperBound().equals(getUpperBound(aClass))) {
capturedWildcard.getUpperBound().equals(TypeConversionUtil.getUpperBound(aClass))) {
eqBound = capturedWildcard;
}
}
@@ -109,7 +109,7 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
if (myT.equals(conjunct)) return true;
}
}
final PsiType lowerBound = InferenceSession.getLowerBound(CClass);
final PsiType lowerBound = TypeConversionUtil.getLowerBound(CClass);
if (lowerBound != null) {
constraints.add(new StrictSubtypingConstraint(lowerBound, myS, myCapture));
return true;
@@ -0,0 +1,8 @@
class Test {
private static Class<? extends Object[]> test(Class<?> arrayType) {
return arrayType.asSubclass(Object[].class);
}
}
@@ -1014,6 +1014,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testArrayTypeUpperBound() { doTest(); }
public void testNonGenericInnerOfGenericOuter() { doTest(); }
public void testTypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked() {