diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt index 6309f8c9f93..4f754c6c2c5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts import com.google.common.collect.* +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -251,6 +252,13 @@ internal class DelegatingDataFlowInfo @JvmOverloads constructor( return DelegatingDataFlowInfo(this, ImmutableMap.copyOf(nullabilityMapBuilder), otherTypeInfo) } + private fun Set.containsNothing() = any { KotlinBuiltIns.isNothing(it) } + + private fun Set.intersect(other: Set) = + if (other.containsNothing()) this + else if (this.containsNothing()) other + else Sets.intersection(this, other) + override fun or(otherInfo: DataFlowInfo): DataFlowInfo { if (otherInfo === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY if (this === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY @@ -270,9 +278,7 @@ internal class DelegatingDataFlowInfo @JvmOverloads constructor( val newTypeInfo = newTypeInfo() for (key in Sets.intersection(myTypeInfo.keySet(), otherTypeInfo.keySet())) { - val thisTypes = myTypeInfo.get(key) - val otherTypes = otherTypeInfo.get(key) - newTypeInfo.putAll(key, Sets.intersection(thisTypes, otherTypes)) + newTypeInfo.putAll(key, myTypeInfo[key].intersect(otherTypeInfo[key])) } if (nullabilityMapBuilder.isEmpty() && newTypeInfo.isEmpty) { diff --git a/compiler/testData/codegen/box/when/typeDisjunction.kt b/compiler/testData/codegen/box/when/typeDisjunction.kt new file mode 100644 index 00000000000..1d2910393b0 --- /dev/null +++ b/compiler/testData/codegen/box/when/typeDisjunction.kt @@ -0,0 +1,15 @@ +fun foo(s: Any): String { + val x = when (s) { + is String -> s + is Int -> "$s" + else -> return "" + } + + val y: String = x + return y +} + +fun box() = if (foo("OK") == "OK" && foo(42) == "42" && foo(true) == "") "OK" else "Fail" + + + diff --git a/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.kt b/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.kt new file mode 100644 index 00000000000..437ca0d909d --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.kt @@ -0,0 +1,21 @@ +fun foo(s: Any): String { + val x = when (s) { + is String -> s + is Int -> "$s" + else -> return "" + } + + val y: String = x // should be Ok + return y +} + +fun bar(s: Any): String { + val x = when (s) { + is String -> s as String // meaningless + is Int -> "$s" + else -> return "" + } + + val y: String = x // no error + return y +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.txt b/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.txt new file mode 100644 index 00000000000..a6265b3a65a --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.txt @@ -0,0 +1,4 @@ +package + +public fun bar(/*0*/ s: kotlin.Any): kotlin.String +public fun foo(/*0*/ s: kotlin.Any): kotlin.String diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 20425acbf6a..602ac52763f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18617,6 +18617,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt"); doTest(fileName); } + + @TestMetadata("WhenTypeDisjunctions.kt") + public void testWhenTypeDisjunctions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 7e7a56d0e83..b870dfc16b7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -8389,6 +8389,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("typeDisjunction.kt") + public void testTypeDisjunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/typeDisjunction.kt"); + doTest(fileName); + } + @TestMetadata("whenArgumentIsEvaluatedOnlyOnce.kt") public void testWhenArgumentIsEvaluatedOnlyOnce() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/whenArgumentIsEvaluatedOnlyOnce.kt");