From 41d2f41141ab9824c6b51388da0a1c34630f6be9 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 18 Feb 2020 12:11:03 +0300 Subject: [PATCH] [FIR] Fix incorrect smartcasts from || expressions #KT-36057 Fixed --- .../kotlin/fir/resolve/dfa/LogicSystem.kt | 6 ++-- .../resolve/smartcasts/orInWhenBranch.kt | 27 ++++++++++++++ .../resolve/smartcasts/orInWhenBranch.txt | 35 +++++++++++++++++++ .../fir/FirDiagnosticsTestGenerated.java | 5 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 5 +++ .../diagnostics/tests/infos/SmartCasts.fir.kt | 2 +- 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt create mode 100644 compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 44910dcdf8a..2972b83c313 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -137,8 +137,10 @@ abstract class LogicSystem(protected val context: ConeInferenceCont val allTypes = types.flatMapTo(mutableSetOf()) { it } val commonTypes = allTypes.toMutableSet() types.forEach { commonTypes.retainAll(it) } - val differentTypes = allTypes - commonTypes - context.commonSuperTypeOrNull(differentTypes.toList())?.let { commonTypes += it } + val differentTypes = types.mapNotNull { (it - commonTypes).takeIf { it.isNotEmpty() } } + if (differentTypes.size == types.size) { + context.commonSuperTypeOrNull(differentTypes.flatten())?.let { commonTypes += it } + } return commonTypes } } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt b/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt new file mode 100644 index 00000000000..c681c1b2959 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt @@ -0,0 +1,27 @@ +// ISSUE: KT-36057 + +fun String.foo() {} + +fun test_1(a: Any?) { + when (a) { + is String, is Any -> a.foo() // Should be Bad + } +} + +fun test_2(a: Any?) { + if (a is String || a is Any) { + a.foo() // Should be Bad + } +} + +fun test_3(a: Any?, b: Boolean) { + when (a) { + is String, b -> a.foo() // Should be Bad + } +} + +fun test_4(a: Any?, b: Boolean) { + if (a is String || b) { + a.foo() // Should be Bad + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.txt b/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.txt new file mode 100644 index 00000000000..0adf2def51c --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.txt @@ -0,0 +1,35 @@ +FILE: orInWhenBranch.kt + public final fun R|kotlin/String|.foo(): R|kotlin/Unit| { + } + public final fun test_1(a: R|kotlin/Any?|): R|kotlin/Unit| { + when (R|/a|) { + ($subj$ is R|kotlin/String|) || ($subj$ is R|kotlin/Any|) -> { + R|/a|.#() + } + } + + } + public final fun test_2(a: R|kotlin/Any?|): R|kotlin/Unit| { + when () { + (R|/a| is R|kotlin/String|) || (R|/a| is R|kotlin/Any|) -> { + R|/a|.#() + } + } + + } + public final fun test_3(a: R|kotlin/Any?|, b: R|kotlin/Boolean|): R|kotlin/Unit| { + when (R|/a|) { + ($subj$ is R|kotlin/String|) || ==($subj$, R|/b|) -> { + R|/a|.#() + } + } + + } + public final fun test_4(a: R|kotlin/Any?|, b: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + (R|/a| is R|kotlin/String|) || R|/b| -> { + R|/a|.#() + } + } + + } 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 38e56c5c4e0..6dff802afdc 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -1461,6 +1461,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt"); } + @TestMetadata("orInWhenBranch.kt") + public void testOrInWhenBranch() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt"); + } + @TestMetadata("smartCastInInit.kt") public void testSmartCastInInit() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/smartCastInInit.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 aa8d116f38f..fd54972989b 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1461,6 +1461,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt"); } + @TestMetadata("orInWhenBranch.kt") + public void testOrInWhenBranch() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/smartcasts/orInWhenBranch.kt"); + } + @TestMetadata("smartCastInInit.kt") public void testSmartCastInInit() throws Exception { runTest("compiler/fir/resolve/testData/resolve/smartcasts/smartCastInInit.kt"); diff --git a/compiler/testData/diagnostics/tests/infos/SmartCasts.fir.kt b/compiler/testData/diagnostics/tests/infos/SmartCasts.fir.kt index e719d154b20..f1075938464 100644 --- a/compiler/testData/diagnostics/tests/infos/SmartCasts.fir.kt +++ b/compiler/testData/diagnostics/tests/infos/SmartCasts.fir.kt @@ -196,7 +196,7 @@ fun mergeSmartCasts(a: Any?) { a.compareTo("") } when (a) { - is String, is Any -> a.compareTo("") + is String, is Any -> a.compareTo("") } if (a is String && a is Any) { val i: Int = a.compareTo("")