From 76931affc6309013d076e98e08bc8c8e3edda1cc Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 27 Nov 2015 18:35:02 +0300 Subject: [PATCH] KT-10139: Non-exhaustive 'when' without 'else' used in expression is an error regardless of expected type: it can't be an expression, even of type Unit. --- .../org/jetbrains/kotlin/cfg/WhenChecker.java | 7 +----- .../rendering/DefaultErrorMessages.java | 2 +- .../codegen/box/when/noElseAssigned.kt | 9 ------- .../codegen/box/when/noElseAssignedNoMatch.kt | 9 ------- .../box/when/noElseInRetunedExpression.kt | 11 --------- .../when/noElseInRetunedExpressionNoMatch.kt | 11 --------- .../controlStructures/ifWhenWithoutElse.kt | 19 ++++++++++++--- .../controlStructures/ifWhenWithoutElse.txt | 12 ++++++++++ .../tests/when/NoElseExpectedUnit.kt | 2 +- .../tests/when/NoElseReturnedUnit.kt | 2 +- .../BlackBoxCodegenTestGenerated.java | 24 ------------------- .../kotlin/console/HistoryKeyListener.kt | 10 ++++---- 12 files changed, 38 insertions(+), 80 deletions(-) delete mode 100644 compiler/testData/codegen/box/when/noElseAssigned.kt delete mode 100644 compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt delete mode 100644 compiler/testData/codegen/box/when/noElseInRetunedExpression.kt delete mode 100644 compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java index 2484706fa48..2b39973ba75 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java @@ -48,12 +48,7 @@ public final class WhenChecker { } public static boolean mustHaveElse(@NotNull KtWhenExpression expression, @NotNull BindingTrace trace) { - KotlinType expectedType = trace.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression); - boolean isUnit = expectedType != null && KotlinBuiltIns.isUnit(expectedType); - // Some "statements" are actually expressions returned from lambdas, their expected types are non-null - boolean isStatement = BindingContextUtilsKt.isUsedAsStatement(expression, trace.getBindingContext()) && expectedType == null; - - return !isUnit && !isStatement && !isWhenExhaustive(expression, trace); + return !BindingContextUtilsKt.isUsedAsStatement(expression, trace.getBindingContext()) && !isWhenExhaustive(expression, trace); } public static boolean isWhenByEnum(@NotNull KtWhenExpression expression, @NotNull BindingContext context) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 93da447ef41..4b92e663076 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -416,7 +416,7 @@ public class DefaultErrorMessages { MAP.put(ELSE_MISPLACED_IN_WHEN, "'else' entry must be the last one in a when-expression"); MAP.put(COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT, "Deprecated syntax. Use '||' instead of commas in when-condition for 'when' without argument"); - MAP.put(NO_ELSE_IN_WHEN, "'when' expression must contain 'else' branch"); + MAP.put(NO_ELSE_IN_WHEN, "'when' expression must be exhaustive or contain an 'else' branch"); MAP.put(NON_EXHAUSTIVE_WHEN, "'when' expression contains only some variants and no 'else' branch"); MAP.put(TYPE_MISMATCH_IN_RANGE, "Type mismatch: incompatible types of range and element checked in it"); diff --git a/compiler/testData/codegen/box/when/noElseAssigned.kt b/compiler/testData/codegen/box/when/noElseAssigned.kt deleted file mode 100644 index 40a0dc030bc..00000000000 --- a/compiler/testData/codegen/box/when/noElseAssigned.kt +++ /dev/null @@ -1,9 +0,0 @@ -fun box(): String { - var r = "Fail 0" - val x = 1 - val y: Unit = when (x) { - 1 -> { r = "OK" } - 2 -> { r = "Fail 1" } - } - return r -} \ No newline at end of file diff --git a/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt b/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt deleted file mode 100644 index 1deb4282fde..00000000000 --- a/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -fun box(): String { - var r = "OK" - val x = 3 - val y: Unit = when (x) { - 1 -> { r = "Fail 0" } - 2 -> { r = "Fail 1" } - } - return r -} \ No newline at end of file diff --git a/compiler/testData/codegen/box/when/noElseInRetunedExpression.kt b/compiler/testData/codegen/box/when/noElseInRetunedExpression.kt deleted file mode 100644 index c83cd49bda5..00000000000 --- a/compiler/testData/codegen/box/when/noElseInRetunedExpression.kt +++ /dev/null @@ -1,11 +0,0 @@ -var r = "Fail 0" - -fun foo(x: Int) { - return when (x) { - 1 -> { r = "OK" } - } -} -fun box(): String { - foo(1) - return r -} \ No newline at end of file diff --git a/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt b/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt deleted file mode 100644 index 6aa447c9e5f..00000000000 --- a/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt +++ /dev/null @@ -1,11 +0,0 @@ -var r = "OK" - -fun foo(x: Int) { - return when (x) { - 1 -> { r = "Fail" } - } -} -fun box(): String { - foo(0) - return r -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.kt b/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.kt index c3afe38c124..97bf88b8ecc 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.kt @@ -19,10 +19,10 @@ val xx6 = null ?: if (true) 42 val xx7 = "" + if (true) 42 val wxx1 = when { true -> 42 } -val wxx2: Unit = when { true -> 42 } +val wxx2: Unit = when { true -> 42 } val wxx3 = idAny(when { true -> 42 }) val wxx4 = id(when { true -> 42 }) -val wxx5 = idUnit(when { true -> 42 }) // TODO illegal expression +val wxx5 = idUnit(when { true -> 42 }) val wxx6 = null ?: when { true -> 42 } val wxx7 = "" + when { true -> 42 } @@ -40,11 +40,24 @@ val ufn4: () -> Unit = { when { true -> 42 } } val ufn5: () -> Unit = { when { true -> mlist.add() } } val ufn6: () -> Unit = { when { true -> work() } } +fun f1() = if (true) work() +fun f2() = if (true) mlist.add() +fun f3() = if (true) 42 +fun f4(): Unit = if (true) work() +fun f5(): Unit = if (true) mlist.add() +fun f6(): Unit = if (true) 42 +fun g1() = when { true -> work() } +fun g2() = when { true -> mlist.add() } +fun g3() = when { true -> 42 } +fun g4(): Unit = when { true -> work() } +fun g5(): Unit = when { true -> mlist.add() } +fun g6(): Unit = when { true -> 42 } + fun foo1(x: String?) { "" + if (true) 42 w@while (true) { x ?: if (true) break - x ?: when { true -> break@w } + x ?: when { true -> break@w } } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.txt b/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.txt index 89e7128aaef..07073b08ba1 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.txt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifWhenWithoutElse.txt @@ -27,8 +27,20 @@ public val xx4: kotlin.Unit public val xx5: kotlin.Unit public val xx6: kotlin.Unit public val xx7: kotlin.String +public fun f1(): kotlin.Unit +public fun f2(): kotlin.Unit +public fun f3(): kotlin.Unit +public fun f4(): kotlin.Unit +public fun f5(): kotlin.Unit +public fun f6(): kotlin.Unit public fun foo1(/*0*/ x: kotlin.String?): kotlin.Unit public fun foo2(): kotlin.Unit +public fun g1(): kotlin.Unit +public fun g2(): kotlin.Boolean +public fun g3(): kotlin.Int +public fun g4(): kotlin.Unit +public fun g5(): kotlin.Unit +public fun g6(): kotlin.Unit public fun id(/*0*/ x: T): T public fun idAny(/*0*/ x: kotlin.Any): kotlin.Any public fun idUnit(/*0*/ x: kotlin.Unit): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/when/NoElseExpectedUnit.kt b/compiler/testData/diagnostics/tests/when/NoElseExpectedUnit.kt index 4b240e601c9..6ec8570e4e4 100644 --- a/compiler/testData/diagnostics/tests/when/NoElseExpectedUnit.kt +++ b/compiler/testData/diagnostics/tests/when/NoElseExpectedUnit.kt @@ -1,5 +1,5 @@ fun foo(x: Int) { - val y: Unit = when (x) { + val y: Unit = when (x) { 2 -> {} 3 -> {} } diff --git a/compiler/testData/diagnostics/tests/when/NoElseReturnedUnit.kt b/compiler/testData/diagnostics/tests/when/NoElseReturnedUnit.kt index 606fe43e816..8260884dd5f 100644 --- a/compiler/testData/diagnostics/tests/when/NoElseReturnedUnit.kt +++ b/compiler/testData/diagnostics/tests/when/NoElseReturnedUnit.kt @@ -1,5 +1,5 @@ fun foo(x: Int) { - return when (x) { + return when (x) { 2 -> {} 3 -> {} } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 371277bd778..a70001a8a20 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -8212,18 +8212,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("noElseAssigned.kt") - public void testNoElseAssigned() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseAssigned.kt"); - doTest(fileName); - } - - @TestMetadata("noElseAssignedNoMatch.kt") - public void testNoElseAssignedNoMatch() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt"); - doTest(fileName); - } - @TestMetadata("noElseExhaustive.kt") public void testNoElseExhaustive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseExhaustive.kt"); @@ -8242,18 +8230,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("noElseInRetunedExpression.kt") - public void testNoElseInRetunedExpression() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseInRetunedExpression.kt"); - doTest(fileName); - } - - @TestMetadata("noElseInRetunedExpressionNoMatch.kt") - public void testNoElseInRetunedExpressionNoMatch() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt"); - doTest(fileName); - } - @TestMetadata("noElseInStatement.kt") public void testNoElseInStatement() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/noElseInStatement.kt"); diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt index 65a52301c6d..70575dc40f0 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/HistoryKeyListener.kt @@ -42,10 +42,12 @@ class HistoryKeyListener( UP, DOWN } - override fun keyReleased(e: KeyEvent): Unit = when (e.keyCode) { - KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP) - KeyEvent.VK_DOWN -> moveHistoryCursor(HistoryMove.DOWN) - KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> prevCaretOffset = consoleEditor.caretModel.offset + override fun keyReleased(e: KeyEvent) { + when (e.keyCode) { + KeyEvent.VK_UP -> moveHistoryCursor(HistoryMove.UP) + KeyEvent.VK_DOWN -> moveHistoryCursor(HistoryMove.DOWN) + KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> prevCaretOffset = consoleEditor.caretModel.offset + } } private fun moveHistoryCursor(move: HistoryMove) {