boolean (@NotNull PsiType fromType, @NotNull PsiType toType, @Nullable LanguageLevel languageLevel) { if (fromType == toType) return true; final boolean fromIsPrimitive = isPrimitiveAndNotNull(fromType); final boolean toIsPrimitive = isPrimitiveAndNotNull(toType); if (fromIsPrimitive || toIsPrimitive) { if (isVoidType(fromType) || isVoidType(toType)) return false; final int fromTypeRank = getTypeRank(fromType); final int toTypeRank = getTypeRank(toType); if (!toIsPrimitive) { if (fromTypeRank == toTypeRank) return true; if (toType instanceof PsiIntersectionType) { for (PsiType type : ((PsiIntersectionType)toType).getConjuncts()) { if (!areTypesConvertible(fromType, type)) return false; } return true; } // JLS 5.5: A value of a primitive type can be cast to a reference type by boxing conversion(see 5.1.7) if (!(toType instanceof PsiClassType)) return false; PsiClass toClass = ((PsiClassType)toType).resolve(); if (toClass == null || toClass instanceof PsiTypeParameter) return false; PsiClassType boxedType = ((PsiPrimitiveType)fromType).getBoxedType(toClass.getManager(), toType.getResolveScope()); return boxedType != null && areTypesConvertible(boxedType, toType); } if (!fromIsPrimitive) { // 5.5. Casting Contexts if ((fromTypeRank == SHORT_RANK || fromTypeRank == BYTE_RANK) && toTypeRank == CHAR_RANK) return false; fromType = uncapture(fromType); //starting from javac 9+ if (fromType instanceof PsiClassType) { if (languageLevel == null) { languageLevel = ((PsiClassType)fromType).getLanguageLevel(); } if (languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) { final PsiClassType classType = (PsiClassType)fromType; final PsiClass psiClass = classType.resolve(); if (psiClass == null) return false; final PsiClassType boxedType = ((PsiPrimitiveType)toType).getBoxedType(psiClass.getManager(), psiClass.getResolveScope()); if (boxedType != null && isNarrowingReferenceConversionAllowed(fromType, boxedType)) { return true; } } //unboxing and widening with type parameters if (fromTypeRank == UNKNOWN_RANK && isUnboxable((PsiPrimitiveType)toType, (PsiClassType)fromType, new HashSet<>())) { return true; } } return fromTypeRank == toTypeRank || fromTypeRank < toTypeRank && toTypeRank <= MAX_NUMERIC_RANK; } return fromTypeRank == toTypeRank || fromTypeRank <= MAX_NUMERIC_RANK && toTypeRank <= MAX_NUMERIC_RANK; } //type can be casted via widening reference conversion if (isAssignable(toType, fromType)) return true; if (isNullType(fromType) || isNullType(toType)) return true; // or narrowing reference conversion return isNarrowingReferenceConversionAllowed(fromType, toType); }