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.
This commit is contained in:
Dmitry Petrov
2015-11-27 18:35:02 +03:00
parent 1a3a296827
commit 76931affc6
12 changed files with 38 additions and 80 deletions
@@ -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) {
@@ -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");
-9
View File
@@ -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
}
@@ -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
}
@@ -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
}
@@ -1,11 +0,0 @@
var r = "OK"
fun foo(x: Int) {
return when (x) {
1 -> { r = "Fail" }
}
}
fun box(): String {
foo(0)
return r
}
@@ -19,10 +19,10 @@ val xx6 = null ?: <!INVALID_IF_AS_EXPRESSION!>if (true) 42<!>
val xx7 = "" + <!INVALID_IF_AS_EXPRESSION!>if (true) 42<!>
val wxx1 = <!NO_ELSE_IN_WHEN!>when<!> { true -> 42 }
val wxx2: Unit = when { true -> <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!> }
val wxx2: Unit = <!NO_ELSE_IN_WHEN!>when<!> { true -> <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!> }
val wxx3 = idAny(<!NO_ELSE_IN_WHEN!>when<!> { true -> 42 })
val wxx4 = id(<!NO_ELSE_IN_WHEN!>when<!> { true -> 42 })
val wxx5 = idUnit(when { true -> 42 }) // TODO illegal expression
val wxx5 = idUnit(<!NO_ELSE_IN_WHEN!>when<!> { true -> 42 })
val wxx6 = null ?: <!NO_ELSE_IN_WHEN!>when<!> { true -> 42 }
val wxx7 = "" + <!NO_ELSE_IN_WHEN!>when<!> { true -> 42 }
@@ -40,11 +40,24 @@ val ufn4: () -> Unit = { when { true -> <!UNUSED_EXPRESSION!>42<!> } }
val ufn5: () -> Unit = { when { true -> mlist.add() } }
val ufn6: () -> Unit = { when { true -> work() } }
fun f1() = <!INVALID_IF_AS_EXPRESSION!>if (true) work()<!>
fun f2() = <!INVALID_IF_AS_EXPRESSION!>if (true) mlist.add()<!>
fun f3() = <!INVALID_IF_AS_EXPRESSION!>if (true) 42<!>
fun f4(): Unit = <!INVALID_IF_AS_EXPRESSION!>if (true) work()<!>
fun f5(): Unit = <!INVALID_IF_AS_EXPRESSION!>if (true) mlist.add()<!>
fun f6(): Unit = <!INVALID_IF_AS_EXPRESSION!>if (true) 42<!>
fun g1() = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!><!NO_ELSE_IN_WHEN!>when<!> { true -> work() }<!>
fun g2() = <!NO_ELSE_IN_WHEN!>when<!> { true -> mlist.add() }
fun g3() = <!NO_ELSE_IN_WHEN!>when<!> { true -> 42 }
fun g4(): Unit = <!NO_ELSE_IN_WHEN!>when<!> { true -> work() }
fun g5(): Unit = <!NO_ELSE_IN_WHEN!>when<!> { true -> <!TYPE_MISMATCH!>mlist.add()<!> }
fun g6(): Unit = <!NO_ELSE_IN_WHEN!>when<!> { true -> <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!> }
fun foo1(x: String?) {
"" + <!INVALID_IF_AS_EXPRESSION!>if (true) 42<!>
w@while (true) {
x ?: if (true) break
x ?: <!NO_ELSE_IN_WHEN!>when<!> { true -> break@w }
x ?: when { true -> break@w }
}
}
@@ -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 </*0*/ T> id(/*0*/ x: T): T
public fun idAny(/*0*/ x: kotlin.Any): kotlin.Any
public fun idUnit(/*0*/ x: kotlin.Unit): kotlin.Unit
@@ -1,5 +1,5 @@
fun foo(x: Int) {
val y: Unit = when (x) {
val y: Unit = <!NO_ELSE_IN_WHEN!>when<!> (x) {
2 -> {}
3 -> {}
}
@@ -1,5 +1,5 @@
fun foo(x: Int) {
return when (x) {
return <!NO_ELSE_IN_WHEN!>when<!> (x) {
2 -> {}
3 -> {}
}
@@ -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");
@@ -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) {