From ed8ccdc15ab482e27ca64f678a94667d53f80e4a Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 28 Jan 2016 14:19:45 +0300 Subject: [PATCH] Take into account data flow info changes for special call (if/when/elvis/!!) arguments #KT-10824 Fixed Smart casts on complex expressions look as no more possible --- .../ControlStructureTypingUtils.java | 2 +- .../box/smartCasts/smartCastInsideIf.kt | 15 ++++++ .../diagnostics/tests/regressions/kt10824.kt | 52 +++++++++++++++++++ .../diagnostics/tests/regressions/kt10824.txt | 13 +++++ .../tests/smartCasts/elvisExprNotNull.kt | 4 +- .../tests/smartCasts/ifCascadeExprNotNull.kt | 6 +-- .../smartCasts/ifExprInConditionNonNull.kt | 4 +- .../smartCasts/ifExprInWhenSubjectNonNull.kt | 8 +-- .../tests/smartCasts/ifExprNonNull.kt | 4 +- .../tests/smartCasts/shortIfExprNotNull.kt | 6 +-- .../tests/smartCasts/smartCastOnIf.kt | 6 +-- .../tests/smartCasts/whenIfExprNonNull.kt | 6 +-- .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../BlackBoxCodegenTestGenerated.java | 6 +++ idea/testData/checker/infos/SmartCastOnIf.kt | 4 +- 15 files changed, 117 insertions(+), 25 deletions(-) create mode 100644 compiler/testData/codegen/box/smartCasts/smartCastInsideIf.kt create mode 100644 compiler/testData/diagnostics/tests/regressions/kt10824.kt create mode 100644 compiler/testData/diagnostics/tests/regressions/kt10824.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java index c9a793a5e29..4232fc198a5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java @@ -187,7 +187,7 @@ public class ControlStructureTypingUtils { @Override public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) { - //todo + dataFlowInfoForArgumentsMap.put(valueArgument, dataFlowInfo); } @NotNull diff --git a/compiler/testData/codegen/box/smartCasts/smartCastInsideIf.kt b/compiler/testData/codegen/box/smartCasts/smartCastInsideIf.kt new file mode 100644 index 00000000000..10d4a4c76c8 --- /dev/null +++ b/compiler/testData/codegen/box/smartCasts/smartCastInsideIf.kt @@ -0,0 +1,15 @@ +class A(val s: String = "FAIL") + +private fun foo(a: A?, aOther: A?): A { + return if (a == null) { + A() + } + else { + if (aOther == null) { + return A() + } + aOther + } +} + +fun box() = foo(A("???"), A("OK")).s diff --git a/compiler/testData/diagnostics/tests/regressions/kt10824.kt b/compiler/testData/diagnostics/tests/regressions/kt10824.kt new file mode 100644 index 00000000000..6c924b0ac8c --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt10824.kt @@ -0,0 +1,52 @@ +// See KT-10824: Smart cast depending on control flow does not work inside `if` +class A +fun foo(a: A?, aOther: A?): A { + return if (a == null) { + A() + } + else { + var newA = aOther + if (newA == null) { + newA = A() + } + newA + } +} +fun bar(a: A?, aOther: A?): A { + return if (a == null) { + A() + } + else { + if (aOther == null) { + return A() + } + + aOther + } +} +fun foo1(a: A?, aOther: A?): A { + val result = if (a == null) { + A() + } + else { + var newA = aOther + if (newA == null) { + newA = A() + } + newA + } + return result +} +fun bar1(a: A?, aOther: A?): A { + val result = if (a == null) { + A() + } + else { + if (aOther == null) { + return A() + } + + aOther + } + return result +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt10824.txt b/compiler/testData/diagnostics/tests/regressions/kt10824.txt new file mode 100644 index 00000000000..d69f0076159 --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt10824.txt @@ -0,0 +1,13 @@ +package + +public fun bar(/*0*/ a: A?, /*1*/ aOther: A?): A +public fun bar1(/*0*/ a: A?, /*1*/ aOther: A?): A +public fun foo(/*0*/ a: A?, /*1*/ aOther: A?): A +public fun foo1(/*0*/ a: A?, /*1*/ aOther: A?): A + +public final class A { + public constructor A() + 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/smartCasts/elvisExprNotNull.kt b/compiler/testData/diagnostics/tests/smartCasts/elvisExprNotNull.kt index 17858940a2a..2a91f6b5f40 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/elvisExprNotNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/elvisExprNotNull.kt @@ -15,10 +15,10 @@ fun bar(s: Any?): String { else { val u: Any? = null if (u !is String) return "" - u + u }) ?: "xyz" // Ideally we should have smart cast to String here - return t + return t } fun baz(s: String?, r: String?): String { diff --git a/compiler/testData/diagnostics/tests/smartCasts/ifCascadeExprNotNull.kt b/compiler/testData/diagnostics/tests/smartCasts/ifCascadeExprNotNull.kt index c9659fabce5..cea0780187c 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/ifCascadeExprNotNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/ifCascadeExprNotNull.kt @@ -5,10 +5,10 @@ fun baz(s: String?): String { else if (s == "") { val u: String? = null if (u == null) return "" - u + u } else { - s + s } - return t + return t } diff --git a/compiler/testData/diagnostics/tests/smartCasts/ifExprInConditionNonNull.kt b/compiler/testData/diagnostics/tests/smartCasts/ifExprInConditionNonNull.kt index f9dae64aa86..1d09b12170f 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/ifExprInConditionNonNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/ifExprInConditionNonNull.kt @@ -1,11 +1,11 @@ fun baz(s: String?, b: Boolean?): String { val t = if (if (b == null) return "" else b) { if (s == null) return "" - s + s } else { if (s != null) return s "" } - return t + return t } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/ifExprInWhenSubjectNonNull.kt b/compiler/testData/diagnostics/tests/smartCasts/ifExprInWhenSubjectNonNull.kt index 9f8903d76c0..66fda025c2d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/ifExprInWhenSubjectNonNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/ifExprInWhenSubjectNonNull.kt @@ -1,11 +1,11 @@ fun baz(s: String?, u: String?): String { val t = when(if (u == null) return "" else u) { - "abc" -> u + "abc" -> u "" -> { if (s == null) return "" - s + s } - else -> u + else -> u } - return t + return t } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/ifExprNonNull.kt b/compiler/testData/diagnostics/tests/smartCasts/ifExprNonNull.kt index 44cd4d835d1..b7060540e99 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/ifExprNonNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/ifExprNonNull.kt @@ -7,9 +7,9 @@ fun baz(s: String?): String { val u: String? = null if (u == null) return "" // !! is detected as unnecessary here - u + u } - return t + return t } fun foo(s: String?): String { diff --git a/compiler/testData/diagnostics/tests/smartCasts/shortIfExprNotNull.kt b/compiler/testData/diagnostics/tests/smartCasts/shortIfExprNotNull.kt index ac79af76ecd..81986d02316 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/shortIfExprNotNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/shortIfExprNotNull.kt @@ -1,9 +1,9 @@ fun baz(s: String?): String { - val t = if (s != null) s + val t = if (s != null) s else { val u: String? = null if (u == null) return "" - u + u } - return t + return t } diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartCastOnIf.kt b/compiler/testData/diagnostics/tests/smartCasts/smartCastOnIf.kt index 57af6a08b3b..037b1750261 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/smartCastOnIf.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/smartCastOnIf.kt @@ -1,10 +1,10 @@ fun baz(s: String?): Int { - return if (s == null) { + return if (s == null) { "" } else { val u: String? = null if (u == null) return 0 - u - }.length + u + }.length } diff --git a/compiler/testData/diagnostics/tests/smartCasts/whenIfExprNonNull.kt b/compiler/testData/diagnostics/tests/smartCasts/whenIfExprNonNull.kt index e17cf49265c..471010ef1aa 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/whenIfExprNonNull.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/whenIfExprNonNull.kt @@ -2,12 +2,12 @@ fun baz(s: String?, u: String?): String { val t = when(s) { is String -> { if (u == null) return s - u + u } else -> { if (u == null) return "" - u + u } } - return t + return t } \ 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 e806ea22094..f874dc1704d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13374,6 +13374,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt10824.kt") + public void testKt10824() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt10824.kt"); + doTest(fileName); + } + @TestMetadata("kt127.kt") public void testKt127() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt127.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 98cf40b13c9..e93f54aba9b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -7363,6 +7363,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("smartCastInsideIf.kt") + public void testSmartCastInsideIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/smartCastInsideIf.kt"); + doTest(fileName); + } + @TestMetadata("whenSmartCast.kt") public void testWhenSmartCast() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/whenSmartCast.kt"); diff --git a/idea/testData/checker/infos/SmartCastOnIf.kt b/idea/testData/checker/infos/SmartCastOnIf.kt index a9be41eb19b..e8dc87a3ece 100644 --- a/idea/testData/checker/infos/SmartCastOnIf.kt +++ b/idea/testData/checker/infos/SmartCastOnIf.kt @@ -1,10 +1,10 @@ fun baz(s: String?): Int { - return if (s == null) { + return if (s == null) { "" } else { val u: String? = null if (u == null) return 0 - u + u }.length }