From b93894953deed940336af55709745047ccabbca7 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 24 Dec 2015 13:23:49 +0300 Subject: [PATCH] Exhaustive whens without else and 'Nothing' as the result are considered 'implicit exhaustive' --- .../types/expressions/PatternMatchingTypingVisitor.java | 6 +++++- compiler/testData/diagnostics/tests/enum/enumStarImport.kt | 4 ++-- compiler/testData/diagnostics/tests/sealed/TreeWhen.kt | 4 ++-- .../diagnostics/tests/when/ExhaustiveBreakContinue.kt | 4 ++-- .../tests/when/ExhaustivePlatformEnumStatement.kt | 4 ++-- .../testData/diagnostics/tests/when/ExhaustiveReturn.kt | 4 ++-- .../diagnostics/tests/when/ExhaustiveReturnThrow.kt | 4 ++-- 7 files changed, 17 insertions(+), 13 deletions(-) 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 e32618b4451..829daa16420 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -145,10 +145,11 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { } } + boolean isExhaustive = WhenChecker.isWhenExhaustive(expression, context.trace); if (commonDataFlowInfo == null) { commonDataFlowInfo = context.dataFlowInfo; } - else if (expression.getElseExpression() == null && !WhenChecker.isWhenExhaustive(expression, context.trace)) { + else if (expression.getElseExpression() == null && !isExhaustive) { // 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); @@ -158,6 +159,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { if (resultType != null) { DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, resultType, context); commonDataFlowInfo = commonDataFlowInfo.assign(resultValue, whenValue); + if (isExhaustive && expression.getElseExpression() == null && KotlinBuiltIns.isNothing(resultType)) { + context.trace.record(BindingContext.IMPLICIT_EXHAUSTIVE_WHEN, expression); + } } return TypeInfoFactoryKt.createTypeInfo(expressionTypes.isEmpty() ? null : components.dataFlowAnalyzer.checkType( components.dataFlowAnalyzer.checkImplicitCast( diff --git a/compiler/testData/diagnostics/tests/enum/enumStarImport.kt b/compiler/testData/diagnostics/tests/enum/enumStarImport.kt index 59cd5488439..99ca9f9419c 100644 --- a/compiler/testData/diagnostics/tests/enum/enumStarImport.kt +++ b/compiler/testData/diagnostics/tests/enum/enumStarImport.kt @@ -13,8 +13,8 @@ import enum.HappyEnum import enum.HappyEnum.* fun f(e: HappyEnum) { - when (e) { + when (e) { CASE1 -> throw UnsupportedOperationException() // unresolved reference CASE2 -> throw UnsupportedOperationException() // unresolved references - } + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/sealed/TreeWhen.kt b/compiler/testData/diagnostics/tests/sealed/TreeWhen.kt index e27f7b50fda..57e0299e8c8 100644 --- a/compiler/testData/diagnostics/tests/sealed/TreeWhen.kt +++ b/compiler/testData/diagnostics/tests/sealed/TreeWhen.kt @@ -4,10 +4,10 @@ sealed class Tree { class Node(val left: Tree, val right: Tree): Tree() fun max(): Int { - when(this) { + when(this) { is Empty -> return -1 is Leaf -> return this.x is Node -> return this.left.max() - } + } } } diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveBreakContinue.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveBreakContinue.kt index 348d97080be..0ecd8c7b8b4 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveBreakContinue.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveBreakContinue.kt @@ -2,11 +2,11 @@ enum class Color { RED, GREEN, BLUE } fun foo(arr: Array): Color { loop@ for (color in arr) { - when (color) { + when (color) { Color.RED -> return color Color.GREEN -> break@loop Color.BLUE -> if (arr.size == 1) return color else continue@loop - } + } // Unreachable return Color.BLUE } diff --git a/compiler/testData/diagnostics/tests/when/ExhaustivePlatformEnumStatement.kt b/compiler/testData/diagnostics/tests/when/ExhaustivePlatformEnumStatement.kt index 744c6fbe580..99817bb4182 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustivePlatformEnumStatement.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustivePlatformEnumStatement.kt @@ -13,8 +13,8 @@ public enum J { // FILE: K.kt fun foo(): Int { - when (J.create()) { + when (J.create()) { J.A -> return 1 J.B -> return 2 - } + } } diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveReturn.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveReturn.kt index 11c764c8ccd..a1dd5472dfa 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveReturn.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveReturn.kt @@ -3,11 +3,11 @@ enum class Direction { } fun foo(dir: Direction): Int { - when (dir) { + when (dir) { Direction.NORTH -> return 1 Direction.SOUTH -> return 2 Direction.WEST -> return 3 Direction.EAST -> return 4 - } + } // See KT-1882: no return is needed at the end } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveReturnThrow.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveReturnThrow.kt index 8dc2ce05aed..2171e817aab 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveReturnThrow.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveReturnThrow.kt @@ -3,12 +3,12 @@ enum class Direction { } fun foo(dir: Direction): Int { - when (dir) { + when (dir) { Direction.NORTH -> return 1 Direction.SOUTH -> throw AssertionError("!!!") Direction.WEST -> return 3 Direction.EAST -> return 4 - } + } // Error: Unreachable code. Return is not required. if (dir == Direction.SOUTH) return 2 } \ No newline at end of file