diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt index 94c16ae1a7d..6fac62246d1 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt @@ -20,8 +20,10 @@ import org.jetbrains.kotlin.cfg.WhenChecker import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtWhenExpression +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -33,8 +35,15 @@ class WhenByPlatformEnumChecker : AdditionalTypeChecker { override fun checkType(expression: KtExpression, expressionType: KotlinType, expressionTypeWithSmartCast: KotlinType, c: ResolutionContext<*>) { if (expression is KtWhenExpression && expression.elseExpression == null) { // Check for conditionally-exhaustive when on platform enums, see KT-6399 - val type = expression.subjectExpression?.let { c.trace.getType(it) } ?: return + val subjectExpression = expression.subjectExpression ?: return + val type = c.trace.getType(subjectExpression) ?: return if (type.isFlexible() && TypeUtils.isNullableType(type.asFlexibleType().upperBound) && !type.annotations.isMarkedNotNull()) { + val dataFlowValue = DataFlowValueFactory.createDataFlowValue(subjectExpression, type, c) + val dataFlowInfo = c.trace[BindingContext.EXPRESSION_TYPE_INFO, subjectExpression]?.dataFlowInfo + if (dataFlowInfo != null && !dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()) { + return + } + val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(type) ?: return val context = c.trace.bindingContext if (WhenChecker.getEnumMissingCases(expression, context, enumClassDescriptor).isEmpty() diff --git a/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.kt b/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.kt index ed89017a4c7..867e95d1cce 100644 --- a/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.kt +++ b/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.kt @@ -27,6 +27,15 @@ fun platformType() = when (J.foo()) { E.B -> 8 } +fun platformTypeSmartCast(): Int { + val e = J.foo() + if (e == null) return -1 + return when (e) { + E.A -> 1 + E.B -> 2 + } +} + // FILE: J.java diff --git a/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.txt b/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.txt index 7c9c46a0d2f..3ada7e25b35 100644 --- a/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.txt +++ b/compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.txt @@ -2,6 +2,7 @@ package public fun nullableNothing(): kotlin.Nothing? public fun platformType(): kotlin.Int +public fun platformTypeSmartCast(): kotlin.Int public fun test(/*0*/ e: E?): kotlin.Int public fun withNull(/*0*/ e: E?): kotlin.Int? public fun withNullableNothing(/*0*/ e: E?): kotlin.Int? diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt index 8cf69c6d2a4..2cc8f8eda8e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.containsTypeAliases import org.jetbrains.kotlin.utils.ifEmpty class SpecifyTypeExplicitlyIntention :