diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt index f1119319e4f..b9bd1cc78e5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.checkReservedPrefixWord import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST +import org.jetbrains.kotlin.resolve.BindingContext.VARIABLE import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -282,8 +283,15 @@ object WhenChecker { @JvmStatic - fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) = - expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) } + fun whenSubjectType(expression: KtWhenExpression, context: BindingContext): KotlinType? { + val subjectVariable = expression.subjectVariable + val subjectExpression = expression.subjectExpression + return when { + subjectVariable != null -> context.get(VARIABLE, subjectVariable)?.type + subjectExpression != null -> context.get(SMARTCAST, subjectExpression)?.defaultType ?: context.getType(subjectExpression) + else -> null + } + } @JvmStatic fun getEnumMissingCases( diff --git a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt index e13cf7c9507..1b9f4988ed8 100644 --- a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt +++ b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt @@ -3,21 +3,16 @@ enum class E { FIRST, SECOND } -fun testSmartcastToEnumInSubjectInitializer(e: E?) { - val x = when (val ne = e!!) { // TODO fix +fun testSmartcastToEnumInSubjectInitializer1(e: E?) { + val x1 = when (val ne = e!!) { E.FIRST -> "f" E.SECOND -> "s" } } - -sealed class Either -class Left : Either() -class Right : Either() - -fun testSmartcastToSealedInSubjectInitializer(x: Any?) { - val y = when (val either = x as Either) { // TODO fix - is Left -> "L" - is Right -> "R" +fun testSmartcastToEnumInSubjectInitializer2(e: E?) { + val x2 = when (val ne: Any = e!!) { // NB explicit type annotation + E.FIRST -> "f" + E.SECOND -> "s" } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.txt b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.txt index e8cf80de574..021c7271b8c 100644 --- a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.txt +++ b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.txt @@ -1,7 +1,7 @@ package -public fun testSmartcastToEnumInSubjectInitializer(/*0*/ e: E?): kotlin.Unit -public fun testSmartcastToSealedInSubjectInitializer(/*0*/ x: kotlin.Any?): kotlin.Unit +public fun testSmartcastToEnumInSubjectInitializer1(/*0*/ e: E?): kotlin.Unit +public fun testSmartcastToEnumInSubjectInitializer2(/*0*/ e: E?): kotlin.Unit public final enum class E : kotlin.Enum { enum entry FIRST @@ -23,24 +23,3 @@ public final enum class E : kotlin.Enum { public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E public final /*synthesized*/ fun values(): kotlin.Array } - -public sealed class Either { - private constructor Either() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - -public final class Left : Either { - public constructor Left() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - -public final class Right : Either { - public constructor Right() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} diff --git a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.kt b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.kt new file mode 100644 index 00000000000..bde8ea93959 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.kt @@ -0,0 +1,20 @@ +// !LANGUAGE: +VariableDeclarationInWhenSubject +// !DIAGNOSTICS: -UNUSED_VARIABLE + +sealed class Either +class Left : Either() +class Right : Either() + +fun testSmartcastToSealedInSubjectInitializer1(x: Any?) { + val y1 = when (val either = x as Either) { + is Left -> "L" + is Right -> "R" + } +} + +fun testSmartcastToSealedInSubjectInitializer2(x: Any?) { + val y2 = when (val either: Any = x as Either) { // NB explicit type annotation + is Left -> "L" + is Right -> "R" + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.txt b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.txt new file mode 100644 index 00000000000..d38333c2d27 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.txt @@ -0,0 +1,25 @@ +package + +public fun testSmartcastToSealedInSubjectInitializer1(/*0*/ x: kotlin.Any?): kotlin.Unit +public fun testSmartcastToSealedInSubjectInitializer2(/*0*/ x: kotlin.Any?): kotlin.Unit + +public sealed class Either { + private constructor Either() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Left : Either { + public constructor Left() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Right : Either { + public constructor Right() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b52d5a38296..c71cb36c26a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -22520,6 +22520,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToEnum.kt"); } + @TestMetadata("smartcastToSealed.kt") + public void testSmartcastToSealed() throws Exception { + runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartcastToSealed.kt"); + } + @TestMetadata("softModifierName.kt") public void testSoftModifierName() throws Exception { runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/softModifierName.kt");