Fix regression on smart casts in when on a sealed class
See the comment in PatternMatchingTypingVisitor
#KT-27221 Fixed
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt
index 248b6e2..0203999 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt
@@ -410,7 +410,13 @@
possibleTypesForSubject: Set<KotlinType>
) {
val subjectExpression = expression.subjectExpression ?: return
- for (possibleCastType in possibleTypesForSubject) {
+ // Using "reversed()" here is a kind of hack to fix KT-27221
+ // KT-27221 was a breaking change introduced after DataFlowImpl optimization that changed the order of possible types to reversed,
+ // and it led to the wrong sealed class being chosen.
+ // But it seems that order of collected types shouldn't matter at all
+ // (at least because the order of relevant checks might change the behavior, see KT-27252)
+ // TODO: Read the comment above, wait for resolution in KT-27252 and get rid of "reversed" call here
+ for (possibleCastType in possibleTypesForSubject.reversed()) {
val possibleCastClass = possibleCastType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
if (possibleCastClass.kind == ClassKind.ENUM_CLASS || possibleCastClass.modality == Modality.SEALED) {
if (checkSmartCastToExpectedTypeInSubject(
diff --git a/compiler/testData/diagnostics/tests/smartCasts/kt27221.kt b/compiler/testData/diagnostics/tests/smartCasts/kt27221.kt
new file mode 100644
index 0000000..c234137
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/smartCasts/kt27221.kt
@@ -0,0 +1,28 @@
+// !DIAGNOSTICS: -UNUSED_VARIABLE
+// SKIP_TXT
+
+sealed class A
+sealed class B : A()
+sealed class C : B()
+object BB : B()
+object CC : C()
+
+fun foo(a: A) {
+ if (a is B) {
+ if (a is C) {
+ val t = when (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is CC -> "CC"
+ }
+ }
+ }
+}
+
+fun foo2(a: A) {
+ if (a is C) {
+ if (<!USELESS_IS_CHECK!>a is B<!>) {
+ val t = when (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is CC -> "CC"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/smartCasts/kt27221_2.kt b/compiler/testData/diagnostics/tests/smartCasts/kt27221_2.kt
new file mode 100644
index 0000000..c209afa
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/smartCasts/kt27221_2.kt
@@ -0,0 +1,36 @@
+// !DIAGNOSTICS: -UNUSED_VARIABLE
+// SKIP_TXT
+
+sealed class A
+sealed class B : A()
+sealed class C : B()
+sealed class D : C()
+object BB : B()
+object CC : C()
+object DD : D()
+
+fun foo1(a: A) {
+ if (a is B) {
+ if (a is D) {
+ if (<!USELESS_IS_CHECK!>a is C<!>) {
+ val t =
+ when (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is DD -> "DD"
+ }
+ }
+ }
+ }
+}
+
+fun foo2(a: A) {
+ if (a is B) {
+ if (a is D) {
+ if (<!USELESS_IS_CHECK!>a is C<!>) {
+ val t =
+ when (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is DD -> "DD"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/smartCasts/kt27221_irrelevantClasses.kt b/compiler/testData/diagnostics/tests/smartCasts/kt27221_irrelevantClasses.kt
new file mode 100644
index 0000000..3a11708
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/smartCasts/kt27221_irrelevantClasses.kt
@@ -0,0 +1,28 @@
+// !DIAGNOSTICS: -UNUSED_VARIABLE
+// SKIP_TXT
+
+sealed class A
+sealed class B : A()
+sealed class C : A()
+object BB : B()
+object CC : C()
+
+fun foo(a: A) {
+ if (a is B) {
+ if (a is C) {
+ val t = when (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is CC -> "CC"
+ }
+ }
+ }
+}
+
+fun foo2(a: A) {
+ if (a is C) {
+ if (a is B) {
+ val t = <!NO_ELSE_IN_WHEN!>when<!> (<!DEBUG_INFO_SMARTCAST!>a<!>) {
+ is CC -> "CC"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
index 6e05e9a..2a3eec1 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
@@ -19014,6 +19014,21 @@
runTest("compiler/testData/diagnostics/tests/smartCasts/kt2422.kt");
}
+ @TestMetadata("kt27221.kt")
+ public void testKt27221() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221.kt");
+ }
+
+ @TestMetadata("kt27221_2.kt")
+ public void testKt27221_2() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221_2.kt");
+ }
+
+ @TestMetadata("kt27221_irrelevantClasses.kt")
+ public void testKt27221_irrelevantClasses() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221_irrelevantClasses.kt");
+ }
+
@TestMetadata("kt2865.kt")
public void testKt2865() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/kt2865.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
index fc49592..13797ec 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
@@ -19014,6 +19014,21 @@
runTest("compiler/testData/diagnostics/tests/smartCasts/kt2422.kt");
}
+ @TestMetadata("kt27221.kt")
+ public void testKt27221() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221.kt");
+ }
+
+ @TestMetadata("kt27221_2.kt")
+ public void testKt27221_2() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221_2.kt");
+ }
+
+ @TestMetadata("kt27221_irrelevantClasses.kt")
+ public void testKt27221_irrelevantClasses() throws Exception {
+ runTest("compiler/testData/diagnostics/tests/smartCasts/kt27221_irrelevantClasses.kt");
+ }
+
@TestMetadata("kt2865.kt")
public void testKt2865() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/kt2865.kt");