Exhaustive whens without else and 'Nothing' as the result are considered 'implicit exhaustive'

This commit is contained in:
Mikhail Glukhikh
2015-12-24 13:23:49 +03:00
committed by Mikhail Glukhikh
parent d62d7dd84f
commit b93894953d
7 changed files with 17 additions and 13 deletions
@@ -145,10 +145,11 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
} }
} }
boolean isExhaustive = WhenChecker.isWhenExhaustive(expression, context.trace);
if (commonDataFlowInfo == null) { if (commonDataFlowInfo == null) {
commonDataFlowInfo = context.dataFlowInfo; 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, // 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 // because data flow can bypass all when branches in this case
commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo); commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo);
@@ -158,6 +159,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (resultType != null) { if (resultType != null) {
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, resultType, context); DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, resultType, context);
commonDataFlowInfo = commonDataFlowInfo.assign(resultValue, whenValue); 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( return TypeInfoFactoryKt.createTypeInfo(expressionTypes.isEmpty() ? null : components.dataFlowAnalyzer.checkType(
components.dataFlowAnalyzer.checkImplicitCast( components.dataFlowAnalyzer.checkImplicitCast(
+2 -2
View File
@@ -13,8 +13,8 @@ import enum.HappyEnum
import enum.HappyEnum.* import enum.HappyEnum.*
fun f(e: HappyEnum) { fun f(e: HappyEnum) {
when (e) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when (e) {
CASE1 -> throw UnsupportedOperationException() // unresolved reference CASE1 -> throw UnsupportedOperationException() // unresolved reference
CASE2 -> throw UnsupportedOperationException() // unresolved references CASE2 -> throw UnsupportedOperationException() // unresolved references
} }<!>
} }
+2 -2
View File
@@ -4,10 +4,10 @@ sealed class Tree {
class Node(val left: Tree, val right: Tree): Tree() class Node(val left: Tree, val right: Tree): Tree()
fun max(): Int { fun max(): Int {
when(this) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when(this) {
is Empty -> return -1 is Empty -> return -1
is Leaf -> return <!DEBUG_INFO_SMARTCAST!>this<!>.x is Leaf -> return <!DEBUG_INFO_SMARTCAST!>this<!>.x
is Node -> return <!DEBUG_INFO_SMARTCAST!>this<!>.left.max() is Node -> return <!DEBUG_INFO_SMARTCAST!>this<!>.left.max()
} }<!>
} }
} }
@@ -2,11 +2,11 @@ enum class Color { RED, GREEN, BLUE }
fun foo(arr: Array<Color>): Color { fun foo(arr: Array<Color>): Color {
loop@ for (color in arr) { loop@ for (color in arr) {
when (color) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when (color) {
Color.RED -> return color Color.RED -> return color
Color.GREEN -> break@loop Color.GREEN -> break@loop
Color.BLUE -> if (arr.size == 1) return color else continue@loop Color.BLUE -> if (arr.size == 1) return color else continue@loop
} }<!>
// Unreachable // Unreachable
<!UNREACHABLE_CODE!>return Color.BLUE<!> <!UNREACHABLE_CODE!>return Color.BLUE<!>
} }
@@ -13,8 +13,8 @@ public enum J {
// FILE: K.kt // FILE: K.kt
fun foo(): Int { fun foo(): Int {
when (<!WHEN_ENUM_CAN_BE_NULL_IN_JAVA!>J.create()<!>) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when (<!WHEN_ENUM_CAN_BE_NULL_IN_JAVA!>J.create()<!>) {
J.A -> return 1 J.A -> return 1
J.B -> return 2 J.B -> return 2
} }<!>
} }
@@ -3,11 +3,11 @@ enum class Direction {
} }
fun foo(dir: Direction): Int { fun foo(dir: Direction): Int {
when (dir) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when (dir) {
Direction.NORTH -> return 1 Direction.NORTH -> return 1
Direction.SOUTH -> return 2 Direction.SOUTH -> return 2
Direction.WEST -> return 3 Direction.WEST -> return 3
Direction.EAST -> return 4 Direction.EAST -> return 4
} }<!>
// See KT-1882: no return is needed at the end // See KT-1882: no return is needed at the end
} }
@@ -3,12 +3,12 @@ enum class Direction {
} }
fun foo(dir: Direction): Int { fun foo(dir: Direction): Int {
when (dir) { <!DEBUG_INFO_IMPLICIT_EXHAUSTIVE!>when (dir) {
Direction.NORTH -> return 1 Direction.NORTH -> return 1
Direction.SOUTH -> throw AssertionError("!!!") Direction.SOUTH -> throw AssertionError("!!!")
Direction.WEST -> return 3 Direction.WEST -> return 3
Direction.EAST -> return 4 Direction.EAST -> return 4
} }<!>
// Error: Unreachable code. Return is not required. // Error: Unreachable code. Return is not required.
<!UNREACHABLE_CODE!>if (dir == Direction.SOUTH) return 2<!> <!UNREACHABLE_CODE!>if (dir == Direction.SOUTH) return 2<!>
} }