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:
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+16
-3
@@ -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 -> {}
|
||||
}
|
||||
|
||||
-24
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user