Improve warnings related to type parameter bounds nullability
Explicitly supply the type parameter that needs to be non-nullified ^KT-36770 Relates
This commit is contained in:
+11
-13
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
import org.jetbrains.kotlin.cfg.WhenChecker
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -54,9 +55,10 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
|
||||
}
|
||||
|
||||
if (isWrongTypeParameterNullabilityForSubtyping(expressionType, c) { dataFlowValue }) {
|
||||
c.trace.report(ErrorsJvm.NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER.on(expression, expressionType))
|
||||
findTypeParameterWithWrongBoundsNullability(expressionType, c) { dataFlowValue }?.let { typeParameterDescriptor ->
|
||||
c.trace.report(ErrorsJvm.NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER.on(expression, typeParameterDescriptor))
|
||||
}
|
||||
|
||||
doCheckType(
|
||||
expressionType,
|
||||
c.expectedType,
|
||||
@@ -154,15 +156,15 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWrongTypeParameterNullabilityForSubtyping(
|
||||
private fun findTypeParameterWithWrongBoundsNullability(
|
||||
expressionType: KotlinType,
|
||||
c: ResolutionContext<*>,
|
||||
dataFlowValueForWholeExpression: () -> DataFlowValue
|
||||
): Boolean {
|
||||
if (c.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated)) return false
|
||||
if (TypeUtils.noExpectedType(c.expectedType)) return false
|
||||
): TypeParameterDescriptor? {
|
||||
if (c.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated)) return null
|
||||
if (TypeUtils.noExpectedType(c.expectedType)) return null
|
||||
|
||||
var metWrongNullabilityInsideArguments = false
|
||||
var foundSubtypeTypeParameter: TypeParameterDescriptor? = null
|
||||
|
||||
@OptIn(ClassicTypeCheckerStateInternals::class)
|
||||
val typeState: TypeCheckerState = object : ClassicTypeCheckerState(isErrorTypeEqualsToAnything = true) {
|
||||
@@ -172,7 +174,7 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
if (isNullableTypeAgainstNotNullTypeParameter(subType as KotlinType, superType as KotlinType)) {
|
||||
// data flow value is only checked for top-level types
|
||||
if (expectsTypeArgument || c.dataFlowInfo.getStableNullability(dataFlowValueForWholeExpression()) != Nullability.NOT_NULL) {
|
||||
metWrongNullabilityInsideArguments = true
|
||||
foundSubtypeTypeParameter = subType.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -186,7 +188,7 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
|
||||
AbstractTypeChecker.isSubtypeOf(typeState, expressionType, c.expectedType)
|
||||
|
||||
return metWrongNullabilityInsideArguments
|
||||
return foundSubtypeTypeParameter
|
||||
}
|
||||
|
||||
override fun checkReceiver(
|
||||
@@ -268,10 +270,6 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
}
|
||||
|
||||
companion object {
|
||||
val typePreparatorUnwrappingEnhancement: KotlinTypePreparator = object : KotlinTypePreparator() {
|
||||
override fun prepareType(type: KotlinTypeMarker): UnwrappedType =
|
||||
super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap()
|
||||
}
|
||||
val typeCheckerForEnhancedTypes = NewKotlinTypeCheckerImpl(
|
||||
kotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
kotlinTypePreparator = object : KotlinTypePreparator() {
|
||||
|
||||
+27
-6
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
@@ -15,13 +16,15 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypePreparator
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker {
|
||||
private val overridingUtilWithEnhancementUnwrapped =
|
||||
OverridingUtil
|
||||
.createWithTypePreparatorAndCustomSubtype(JavaNullabilityChecker.typePreparatorUnwrappingEnhancement) { subtype, supertype ->
|
||||
!JavaNullabilityChecker.isNullableTypeAgainstNotNullTypeParameter(subtype, supertype)
|
||||
}
|
||||
private val typePreparatorUnwrappingEnhancement: KotlinTypePreparator = object : KotlinTypePreparator() {
|
||||
override fun prepareType(type: KotlinTypeMarker): UnwrappedType =
|
||||
super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap()
|
||||
}
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (descriptor !is CallableMemberDescriptor) return
|
||||
@@ -31,6 +34,18 @@ object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker {
|
||||
|
||||
for (overriddenDescriptor in descriptor.overriddenDescriptors) {
|
||||
if (overriddenDescriptor !is JavaMethodDescriptor) continue
|
||||
|
||||
val relatedTypeParameters = mutableSetOf<TypeParameterDescriptor>()
|
||||
val overridingUtilWithEnhancementUnwrapped =
|
||||
OverridingUtil
|
||||
.createWithTypePreparatorAndCustomSubtype(typePreparatorUnwrappingEnhancement) { subtype, supertype ->
|
||||
!JavaNullabilityChecker.isNullableTypeAgainstNotNullTypeParameter(subtype, supertype).also {
|
||||
if (it) {
|
||||
relatedTypeParameters.addIfNotNull(subtype.constructor.declarationDescriptor as? TypeParameterDescriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip, if even with enhancement unwrapped, it's still a valid override
|
||||
if (overridingUtilWithEnhancementUnwrapped
|
||||
.isOverridableBy(
|
||||
@@ -50,7 +65,13 @@ object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker {
|
||||
topLevelType.getEnhancementDeeply() ?: topLevelType
|
||||
})) ?: overriddenDescriptor
|
||||
|
||||
context.trace.report(ErrorsJvm.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, descriptor, unwrappedOverridden))
|
||||
if (relatedTypeParameters.isNotEmpty()) {
|
||||
context.trace.report(
|
||||
ErrorsJvm.WRONG_TYPE_PARAMETER_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, relatedTypeParameters.first())
|
||||
)
|
||||
} else {
|
||||
context.trace.report(ErrorsJvm.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, descriptor, unwrappedOverridden))
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
+6
-2
@@ -102,10 +102,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
"should be subtype of ''{0}'', substituted type is ''{1}''",
|
||||
RENDER_TYPE, RENDER_TYPE, NAME);
|
||||
MAP.put(NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER,
|
||||
"Type mismatch: value of a nullable type {0} is used where non-nullable type is expected. " +
|
||||
"Type parameter ''{0}'' has nullable upper bounds while non-nullable version is expected. " +
|
||||
"This warning will become an error soon. " +
|
||||
"See https://youtrack.jetbrains.com/issue/KT-36770 for details",
|
||||
RENDER_TYPE
|
||||
NAME
|
||||
);
|
||||
MAP.put(RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
|
||||
"Unsafe use of a nullable receiver of type {0}", RENDER_TYPE);
|
||||
@@ -113,6 +113,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(WRONG_NULLABILITY_FOR_JAVA_OVERRIDE,
|
||||
"Override ''{0}'' has incorrect nullability in its signature comparing with overridden ''{1}''", COMPACT, COMPACT);
|
||||
|
||||
MAP.put(WRONG_TYPE_PARAMETER_NULLABILITY_FOR_JAVA_OVERRIDE,
|
||||
"Type parameter ''{0}'' has nullable upper bound, so override has incorrect signature comparing with a base member with NotNull annotation. " +
|
||||
"Please add a non-nullable upper bound (e.g. Any) to the type parameter. See https://kotlinlang.org/docs/generics.html#upper-bounds for more details",
|
||||
NAME);
|
||||
|
||||
MAP.put(ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR,
|
||||
"An accessor will not be generated for ''{0}'', so the annotation will not be written to the class file", STRING);
|
||||
|
||||
+5
-1
@@ -165,7 +165,7 @@ public interface ErrorsJvm {
|
||||
UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS
|
||||
= DiagnosticFactory3.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtElement, KotlinType> NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER
|
||||
DiagnosticFactory1<KtElement, TypeParameterDescriptor> NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER
|
||||
= DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtElement, KotlinType> RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
|
||||
@@ -173,6 +173,10 @@ public interface ErrorsJvm {
|
||||
|
||||
DiagnosticFactory2<KtModifierListOwner, CallableMemberDescriptor, CallableMemberDescriptor> WRONG_NULLABILITY_FOR_JAVA_OVERRIDE =
|
||||
DiagnosticFactory2.create(WARNING, OVERRIDE_MODIFIER);
|
||||
|
||||
DiagnosticFactory1<KtModifierListOwner, TypeParameterDescriptor> WRONG_TYPE_PARAMETER_NULLABILITY_FOR_JAVA_OVERRIDE =
|
||||
DiagnosticFactory1.create(WARNING, OVERRIDE_MODIFIER);
|
||||
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
Reference in New Issue
Block a user