From 4fb331ecd3671f657dabe373867846685822d9b2 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 26 May 2015 17:37:53 +0300 Subject: [PATCH] Solution for KT-7838: now data flow information at the end of when expression is determined correctly. #KT-7838 Fixed. --- .../PatternMatchingTypingVisitor.java | 5 +++ .../diagnostics/tests/when/BranchBypassVal.kt | 11 ++++++ .../tests/when/BranchBypassVal.txt | 10 +++++ .../diagnostics/tests/when/BranchBypassVar.kt | 11 ++++++ .../tests/when/BranchBypassVar.txt | 10 +++++ .../tests/when/BranchFalseBypass.kt | 12 ++++++ .../tests/when/BranchFalseBypass.txt | 37 +++++++++++++++++++ .../tests/when/BranchFalseBypassElse.kt | 12 ++++++ .../tests/when/BranchFalseBypassElse.txt | 10 +++++ .../checkers/JetDiagnosticsTestGenerated.java | 24 ++++++++++++ 10 files changed, 142 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/when/BranchBypassVal.kt create mode 100644 compiler/testData/diagnostics/tests/when/BranchBypassVal.txt create mode 100644 compiler/testData/diagnostics/tests/when/BranchBypassVar.kt create mode 100644 compiler/testData/diagnostics/tests/when/BranchBypassVar.txt create mode 100644 compiler/testData/diagnostics/tests/when/BranchFalseBypass.kt create mode 100644 compiler/testData/diagnostics/tests/when/BranchFalseBypass.txt create mode 100644 compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.kt create mode 100644 compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java index a07f8068bb6..130003a923e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -130,6 +130,11 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { if (commonDataFlowInfo == null) { commonDataFlowInfo = context.dataFlowInfo; } + else if (expression.getElseExpression() == null && !WhenChecker.isWhenExhaustive(expression, context.trace)) { + // Without else expression in non-exhaustive when, we *must* take initial data flow info into account, + // because data flow can bypass all when branches in this case + commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo); + } return TypeInfoFactoryPackage.createTypeInfo(expressionTypes.isEmpty() ? null : DataFlowUtils.checkType( DataFlowUtils.checkImplicitCast( diff --git a/compiler/testData/diagnostics/tests/when/BranchBypassVal.kt b/compiler/testData/diagnostics/tests/when/BranchBypassVal.kt new file mode 100644 index 00000000000..927a3ca63f0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchBypassVal.kt @@ -0,0 +1,11 @@ +class A + +fun test(a: Any): String { + val q: String? = null + + when (a) { + is A -> q!! + } + // When is not exhaustive + return q +} diff --git a/compiler/testData/diagnostics/tests/when/BranchBypassVal.txt b/compiler/testData/diagnostics/tests/when/BranchBypassVal.txt new file mode 100644 index 00000000000..88cb94bd8ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchBypassVal.txt @@ -0,0 +1,10 @@ +package + +internal fun test(/*0*/ a: kotlin.Any): kotlin.String + +internal 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/when/BranchBypassVar.kt b/compiler/testData/diagnostics/tests/when/BranchBypassVar.kt new file mode 100644 index 00000000000..b6102eb462f --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchBypassVar.kt @@ -0,0 +1,11 @@ +class A + +fun test(a: Any) { + var q: String? = null + + when (a) { + is A -> q = "1" + } + // When is not exhaustive + return q +} diff --git a/compiler/testData/diagnostics/tests/when/BranchBypassVar.txt b/compiler/testData/diagnostics/tests/when/BranchBypassVar.txt new file mode 100644 index 00000000000..d0ff22c2d2b --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchBypassVar.txt @@ -0,0 +1,10 @@ +package + +internal fun test(/*0*/ a: kotlin.Any): kotlin.Unit + +internal 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/when/BranchFalseBypass.kt b/compiler/testData/diagnostics/tests/when/BranchFalseBypass.kt new file mode 100644 index 00000000000..8416dc804d1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchFalseBypass.kt @@ -0,0 +1,12 @@ +enum class My { A, B } + +fun test(a: My): String { + val q: String? + + when (a) { + My.A -> q = "1" + My.B -> q = "2" + } + // When is exhaustive + return q +} diff --git a/compiler/testData/diagnostics/tests/when/BranchFalseBypass.txt b/compiler/testData/diagnostics/tests/when/BranchFalseBypass.txt new file mode 100644 index 00000000000..f6d77ab7236 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchFalseBypass.txt @@ -0,0 +1,37 @@ +package + +internal fun test(/*0*/ a: My): kotlin.String + +internal final enum class My : kotlin.Enum { + public enum entry A : My { + private constructor A() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: My): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public enum entry B : My { + private constructor B() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: My): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + private constructor My() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: My): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): My + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.kt b/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.kt new file mode 100644 index 00000000000..243c604e05e --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.kt @@ -0,0 +1,12 @@ +class A + +fun test(a: Any): String { + var q: String? + + when (a) { + is A -> q = "1" + else -> q = "2" + } + // When is not exhaustive + return q +} diff --git a/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.txt b/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.txt new file mode 100644 index 00000000000..88cb94bd8ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.txt @@ -0,0 +1,10 @@ +package + +internal fun test(/*0*/ a: kotlin.Any): kotlin.String + +internal 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/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 2ecbd5131ec..b9ebe49aeb1 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -13548,6 +13548,30 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("BranchBypassVal.kt") + public void testBranchBypassVal() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/BranchBypassVal.kt"); + doTest(fileName); + } + + @TestMetadata("BranchBypassVar.kt") + public void testBranchBypassVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/BranchBypassVar.kt"); + doTest(fileName); + } + + @TestMetadata("BranchFalseBypass.kt") + public void testBranchFalseBypass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/BranchFalseBypass.kt"); + doTest(fileName); + } + + @TestMetadata("BranchFalseBypassElse.kt") + public void testBranchFalseBypassElse() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/BranchFalseBypassElse.kt"); + doTest(fileName); + } + @TestMetadata("ElseOnNullableEnum.kt") public void testElseOnNullableEnum() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/ElseOnNullableEnum.kt");