diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index 52f03accf854..9a70a22923c5 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -60,6 +60,8 @@ public class TypeConversionUtil { } }; private static final Key ORIGINAL_CONTEXT = Key.create("ORIGINAL_CONTEXT"); + public static final Key LOWER_BOUND = Key.create("LowBound"); + public static final Key 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); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaClassSupersImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaClassSupersImpl.java index 388db8a94415..d9a86a47aefb 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaClassSupersImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaClassSupersImpl.java @@ -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); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index b1b9102a7364..b73668d2de7d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -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); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 4d71e9bf9446..d0c39a9f6852 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -42,8 +42,6 @@ import java.util.*; public class InferenceSession { private static final Logger LOG = Logger.getInstance(InferenceSession.class); - private static final Key LOWER_BOUND = Key.create("LowBound"); - private static final Key UPPER_BOUND = Key.create("UpperBound"); private static final Key ERASED = Key.create("UNCHECKED_CONVERSION"); private static final Function, 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; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java index 150bfff25548..818b9cdc474e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java @@ -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; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ArrayTypeUpperBound.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ArrayTypeUpperBound.java new file mode 100644 index 000000000000..8a0aad9a935f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ArrayTypeUpperBound.java @@ -0,0 +1,8 @@ + +class Test { + + private static Class test(Class arrayType) { + return arrayType.asSubclass(Object[].class); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index 6c193fb4436d..ba542c6d722b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -1014,6 +1014,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { doTest(); } + public void testArrayTypeUpperBound() { doTest(); } + public void testNonGenericInnerOfGenericOuter() { doTest(); } public void testTypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked() {