diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 2fd6ed303e6..d779ff5dae1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -3725,7 +3725,17 @@ The "returned" value of try expression with no finally is either the last expres } if (!hasElse && nextCondition != null) { v.mark(nextCondition); - throwNewException(CLASS_NO_PATTERN_MATCHED_EXCEPTION); + if (!isStatement) { + // a result is expected + if (Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, expression))) { + // when() is supposed to be exhaustive + throwNewException(CLASS_NO_PATTERN_MATCHED_EXCEPTION); + } + else { + // non-exhaustive when() with no else -> Unit must be expected + StackValue.putUnitInstance(v); + } + } } markLineNumber(expression); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java index f567a9f556b..48e16baa82a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java @@ -65,7 +65,11 @@ public final class WhenChecker { } } } - return isExhaust && notEmpty; + boolean exhaustive = isExhaust && notEmpty; + if (exhaustive) { + trace.record(BindingContext.EXHAUSTIVE_WHEN, expression); + } + return exhaustive; } private static boolean containsEnumEntryCase( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 12b43ed16c9..cc1341d7e5d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -110,6 +110,8 @@ public interface BindingContext { WritableSlice AUTOCAST = Slices.createSimpleSlice(); + WritableSlice EXHAUSTIVE_WHEN = Slices.createSimpleSlice(); + /** * A scope where type of expression has been resolved */ diff --git a/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt b/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt new file mode 100644 index 00000000000..1deb4282fde --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt @@ -0,0 +1,9 @@ +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/noElseExhaustive.kt b/compiler/testData/codegen/box/when/noElseExhaustive.kt new file mode 100644 index 00000000000..cd2bb5e0e3a --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseExhaustive.kt @@ -0,0 +1,9 @@ +enum class En { + A + B +} + +fun box(): String = when(En.A) { + En.A -> "OK" + En.B -> "Fail 1" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/when/noElseExhaustiveStatement.kt b/compiler/testData/codegen/box/when/noElseExhaustiveStatement.kt new file mode 100644 index 00000000000..8ec86667d8a --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseExhaustiveStatement.kt @@ -0,0 +1,12 @@ +enum class En { + A + B +} + +fun box(): String { + when(En.A) { + En.A -> "s1" + En.B -> "s2" + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/when/noElseExhaustiveUnitExpected.kt b/compiler/testData/codegen/box/when/noElseExhaustiveUnitExpected.kt new file mode 100644 index 00000000000..45c41eb4313 --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseExhaustiveUnitExpected.kt @@ -0,0 +1,14 @@ +enum class En { + A + B +} + +fun box(): String { + + val u: Unit = when(En.A) { + En.A -> {} + En.B -> {} + } + + return "OK" +} diff --git a/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt b/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt new file mode 100644 index 00000000000..6aa447c9e5f --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt @@ -0,0 +1,11 @@ +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/codegen/box/when/noElseNoMatch.kt b/compiler/testData/codegen/box/when/noElseNoMatch.kt new file mode 100644 index 00000000000..2c4e803b07b --- /dev/null +++ b/compiler/testData/codegen/box/when/noElseNoMatch.kt @@ -0,0 +1,8 @@ +fun box(): String { + val x = 3 + when (x) { + 1 -> {} + 2 -> {} + } + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 7886f13c495..6f03aefc53c 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -4413,16 +4413,46 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/when/noElseAssigned.kt"); } + @TestMetadata("noElseAssignedNoMatch.kt") + public void testNoElseAssignedNoMatch() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseAssignedNoMatch.kt"); + } + + @TestMetadata("noElseExhaustive.kt") + public void testNoElseExhaustive() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseExhaustive.kt"); + } + + @TestMetadata("noElseExhaustiveStatement.kt") + public void testNoElseExhaustiveStatement() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseExhaustiveStatement.kt"); + } + + @TestMetadata("noElseExhaustiveUnitExpected.kt") + public void testNoElseExhaustiveUnitExpected() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseExhaustiveUnitExpected.kt"); + } + @TestMetadata("noElseInRetunedExpression.kt") public void testNoElseInRetunedExpression() throws Exception { doTest("compiler/testData/codegen/box/when/noElseInRetunedExpression.kt"); } + @TestMetadata("noElseInRetunedExpressionNoMatch.kt") + public void testNoElseInRetunedExpressionNoMatch() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseInRetunedExpressionNoMatch.kt"); + } + @TestMetadata("noElseInStatement.kt") public void testNoElseInStatement() throws Exception { doTest("compiler/testData/codegen/box/when/noElseInStatement.kt"); } + @TestMetadata("noElseNoMatch.kt") + public void testNoElseNoMatch() throws Exception { + doTest("compiler/testData/codegen/box/when/noElseNoMatch.kt"); + } + @TestMetadata("nullableWhen.kt") public void testNullableWhen() throws Exception { doTest("compiler/testData/codegen/box/when/nullableWhen.kt");