From 1b479c49a8041e41aa89d340e1be6744a95feed2 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 16 Mar 2020 11:04:44 +0300 Subject: [PATCH] [FIR] Fix exhaustiveness checking for conditions with equals to object #KT-37488 Fixed --- .../FirWhenExhaustivenessTransformer.kt | 12 ++++- .../resolve/exhaustiveness_sealedObject.kt | 24 ++++++++++ .../resolve/exhaustiveness_sealedObject.txt | 45 +++++++++++++++++++ .../fir/FirDiagnosticsTestGenerated.java | 5 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 5 +++ .../ExhaustiveWhenOnNestedSealed.fir.kt | 20 --------- .../sealed/ExhaustiveWhenOnNestedSealed.kt | 1 + 7 files changed, 90 insertions(+), 22 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt create mode 100644 compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.txt delete mode 100644 compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.fir.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt index e083cb4ebdc..c8b68ae8b41 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt @@ -149,8 +149,16 @@ class FirWhenExhaustivenessTransformer(private val bodyResolveComponents: BodyRe override fun visitOperatorCall(operatorCall: FirOperatorCall, data: SealedExhaustivenessData) { if (operatorCall.operation == FirOperation.EQ) { val argument = operatorCall.arguments[1] - if (argument is FirConstExpression<*> && argument.value == null) { - data.containsNull = true + when (argument) { + is FirConstExpression<*> -> { + if (argument.value == null) { + data.containsNull = true + } + } + + is FirResolvedQualifier -> { + argument.typeRef.accept(this, data) + } } } } diff --git a/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt b/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt new file mode 100644 index 00000000000..c3752fb9187 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt @@ -0,0 +1,24 @@ +// ISSUE: KT-37488 + +sealed class A + +class B : A() +object C : A() + +fun takeString(s: String) {} + +fun test_1(a: A) { + val s = when(a) { + is B -> "" + is C -> "" + } + takeString(s) +} + +fun test_2(a: A) { + val s = when(a) { + is B -> "" + C -> "" + } + takeString(s) +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.txt b/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.txt new file mode 100644 index 00000000000..ac004e4505b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.txt @@ -0,0 +1,45 @@ +FILE: exhaustiveness_sealedObject.kt + public sealed class A : R|kotlin/Any| { + private constructor(): R|A| { + super() + } + + } + public final class B : R|A| { + public constructor(): R|B| { + super() + } + + } + public final object C : R|A| { + private constructor(): R|C| { + super() + } + + } + public final fun takeString(s: R|kotlin/String|): R|kotlin/Unit| { + } + public final fun test_1(a: R|A|): R|kotlin/Unit| { + lval s: R|kotlin/String| = when (R|/a|) { + ($subj$ is R|B|) -> { + String() + } + ($subj$ is R|C|) -> { + String() + } + } + + R|/takeString|(R|/s|) + } + public final fun test_2(a: R|A|): R|kotlin/Unit| { + lval s: R|kotlin/String| = when (R|/a|) { + ($subj$ is R|B|) -> { + String() + } + ==($subj$, Q|C|) -> { + String() + } + } + + R|/takeString|(R|/s|) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index dce58886b6d..c49bb1ec67c 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -138,6 +138,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_sealedClass.kt"); } + @TestMetadata("exhaustiveness_sealedObject.kt") + public void testExhaustiveness_sealedObject() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt"); + } + @TestMetadata("extension.kt") public void testExtension() throws Exception { runTest("compiler/fir/resolve/testData/resolve/extension.kt"); diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 37488466d58..8c2e187121a 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -138,6 +138,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_sealedClass.kt"); } + @TestMetadata("exhaustiveness_sealedObject.kt") + public void testExhaustiveness_sealedObject() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/exhaustiveness_sealedObject.kt"); + } + @TestMetadata("extension.kt") public void testExtension() throws Exception { runTest("compiler/fir/resolve/testData/resolve/extension.kt"); diff --git a/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.fir.kt b/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.fir.kt deleted file mode 100644 index 7e1f8c828a1..00000000000 --- a/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ -sealed class Sealed { - object First: Sealed() - sealed class NonFirst { - object Second: NonFirst() - object Third: NonFirst() - object Fourth: Sealed() - } -} - -fun foo(s: Sealed, nf: Sealed.NonFirst): Int { - val si = when(s) { - Sealed.First -> 1 - Sealed.NonFirst.Fourth -> 4 - } - val nfi = when(nf) { - Sealed.NonFirst.Second -> 2 - Sealed.NonFirst.Third -> 3 - } - return si + nfi -} diff --git a/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.kt b/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.kt index d11c19bd2ec..5c261d55bb3 100644 --- a/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.kt +++ b/compiler/testData/diagnostics/tests/sealed/ExhaustiveWhenOnNestedSealed.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL sealed class Sealed { object First: Sealed() sealed class NonFirst {