diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt index 4677b70b5f1..afd6f5d71f4 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.UpperBoundChecker import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo @@ -48,9 +49,7 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio expressionTypeWithSmartCast: KotlinType, c: ResolutionContext<*> ) { - if (expressionType is AbbreviatedType) { - upperBoundChecker.checkBoundsOfExpandedTypeAlias(expressionType.expandedType, expression, c.trace) - } + checkTypeParameterBounds(expression, expressionType, c) val dataFlowValue by lazy(LazyThreadSafetyMode.NONE) { c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c) @@ -122,6 +121,29 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio } } + private fun checkTypeParameterBounds( + expression: KtExpression, + expressionType: KotlinType, + c: ResolutionContext<*> + ) { + if (expressionType is AbbreviatedType) { + upperBoundChecker.checkBoundsOfExpandedTypeAlias(expressionType.expandedType, expression, c.trace) + } + + if (c !is BasicCallResolutionContext || upperBoundChecker !is WarningAwareUpperBoundChecker) return + + val resolvedCall = c.trace.bindingContext[BindingContext.RESOLVED_CALL, c.call] ?: return + + for ((typeParameter, typeArgument) in resolvedCall.typeArguments) { + // continue if we don't have explicit type arguments + val typeReference = c.call.typeArguments.getOrNull(typeParameter.index)?.typeReference ?: continue + + upperBoundChecker.checkBounds( + typeReference, typeArgument, typeParameter, TypeSubstitutor.create(typeArgument), c.trace, withOnlyCheckForWarning = true + ) + } + } + private fun isWrongTypeParameterNullabilityForSubtyping( expressionType: KotlinType, c: ResolutionContext<*>, diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WarningAwareUpperBoundChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WarningAwareUpperBoundChecker.kt index 7c2fababedb..1cf668785b5 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WarningAwareUpperBoundChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WarningAwareUpperBoundChecker.kt @@ -49,7 +49,7 @@ class WarningAwareUpperBoundChecker : UpperBoundChecker() { typeParameterDescriptor: TypeParameterDescriptor, substitutor: TypeSubstitutor, trace: BindingTrace, - typeAliasUsageElement: KtElement?, + typeAliasUsageElement: KtElement? = null, withOnlyCheckForWarning: Boolean = false ) { if (typeParameterDescriptor.upperBounds.isEmpty()) return @@ -71,8 +71,12 @@ class WarningAwareUpperBoundChecker : UpperBoundChecker() { } val enhancedBound = bound.getEnhancementDeeply() ?: continue + val argumentTypeEnhancement = argumentType.getEnhancementDeeply() ?: argumentType - checkBound(enhancedBound, argumentType, argumentReference, substitutor, typeAliasUsageElement, diagnosticsReporterForWarnings) + checkBound( + enhancedBound, argumentTypeEnhancement, argumentReference, + substitutor, typeAliasUsageElement, diagnosticsReporterForWarnings + ) } } } diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.fir.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.fir.kt index 581183552af..9393bafdfdc 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.fir.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.fir.kt @@ -22,24 +22,24 @@ public class Test {} // jspecify_nullness_mismatch, jspecify_nullness_mismatch fun main(a1: A<Any?>, a2: A, b1: B<Any?>, b2: B, x: T): Unit { a1.foo(null) - // jspecify_nullness_mismatch{mute} - a1.bar(null) + // jspecify_nullness_mismatch + a1.bar<T?>(null) a1.bar(x) a2.foo(null) - // jspecify_nullness_mismatch{mute} - a2.bar(null) + // jspecify_nullness_mismatch + a2.bar<T?>(null) a2.bar(x) // jspecify_nullness_mismatch{mute} b1.foo(null) - // jspecify_nullness_mismatch{mute} - b1.bar(null) + // jspecify_nullness_mismatch + b1.bar<T?>(null) b1.bar(x) // jspecify_nullness_mismatch{mute} b2.foo(null) - // jspecify_nullness_mismatch{mute} - b2.bar(null) + // jspecify_nullness_mismatch + b2.bar<T?>(null) b2.bar(x) } diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.kt index 156ae02e400..000e1a5aa54 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/TypeParameterBounds.kt @@ -22,24 +22,24 @@ public class Test {} // jspecify_nullness_mismatch, jspecify_nullness_mismatch fun main(a1: A<Any?>, a2: A, b1: B<Any?>, b2: B, x: T): Unit { a1.foo(null) - // jspecify_nullness_mismatch{mute} - a1.bar(null) + // jspecify_nullness_mismatch + a1.bar<T?>(null) a1.bar(x) a2.foo(null) - // jspecify_nullness_mismatch{mute} - a2.bar(null) + // jspecify_nullness_mismatch + a2.bar<T?>(null) a2.bar(x) // jspecify_nullness_mismatch{mute} b1.foo(null) - // jspecify_nullness_mismatch{mute} - b1.bar(null) + // jspecify_nullness_mismatch + b1.bar<T?>(null) b1.bar(x) // jspecify_nullness_mismatch{mute} b2.foo(null) - // jspecify_nullness_mismatch{mute} - b2.bar(null) + // jspecify_nullness_mismatch + b2.bar<T?>(null) b2.bar(x) } \ No newline at end of file