Implicit exhaustive whens now have exception in else branch #KT-8700 Fixed

This commit is contained in:
Mikhail Glukhikh
2015-12-04 18:43:44 +03:00
committed by Mikhail Glukhikh
parent 011a9f23b9
commit 7d6ccc40c2
16 changed files with 167 additions and 18 deletions
@@ -3801,8 +3801,9 @@ The "returned" value of try expression with no finally is either the last expres
return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
SwitchCodegen switchCodegen =
SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(expression, isStatement, ExpressionCodegen.this);
SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(
expression, isStatement, isExhaustive(expression, isStatement), ExpressionCodegen.this
);
if (switchCodegen != null) {
switchCodegen.generate();
return Unit.INSTANCE;
@@ -3848,9 +3849,7 @@ The "returned" value of try expression with no finally is either the last expres
}
if (!hasElse && nextCondition != null) {
v.mark(nextCondition);
if (!isStatement) {
putUnitInstanceOntoStackForNonExhaustiveWhen(expression);
}
putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement);
}
markLineNumber(expression, isStatement);
@@ -3863,14 +3862,24 @@ The "returned" value of try expression with no finally is either the last expres
});
}
private boolean isExhaustive(@NotNull KtWhenExpression whenExpression, boolean isStatement) {
if (isStatement) {
return Boolean.TRUE.equals(bindingContext.get(BindingContext.IMPLICIT_EXHAUSTIVE_WHEN, whenExpression));
}
else {
return Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, whenExpression));
}
}
public void putUnitInstanceOntoStackForNonExhaustiveWhen(
@NotNull KtWhenExpression expression
@NotNull KtWhenExpression whenExpression,
boolean isStatement
) {
if (Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, expression))) {
if (isExhaustive(whenExpression, isStatement)) {
// when() is supposed to be exhaustive
genThrow(v, "kotlin/NoWhenBranchMatchedException", null);
}
else {
else if (!isStatement) {
// non-exhaustive when() with no else -> Unit must be expected
StackValue.putUnitInstance(v);
}
@@ -30,10 +30,11 @@ public class EnumSwitchCodegen extends SwitchCodegen {
public EnumSwitchCodegen(
@NotNull KtWhenExpression expression,
boolean isStatement,
boolean isExhaustive,
@NotNull ExpressionCodegen codegen,
@NotNull WhenByEnumsMapping mapping
) {
super(expression, isStatement, codegen);
super(expression, isStatement, isExhaustive, codegen);
this.mapping = mapping;
}
@@ -26,9 +26,10 @@ public class IntegralConstantsSwitchCodegen extends SwitchCodegen {
public IntegralConstantsSwitchCodegen(
@NotNull KtWhenExpression expression,
boolean isStatement,
boolean isExhaustive,
@NotNull ExpressionCodegen codegen
) {
super(expression, isStatement, codegen);
super(expression, isStatement, isExhaustive, codegen);
}
@Override
@@ -40,9 +40,10 @@ public class StringSwitchCodegen extends SwitchCodegen {
public StringSwitchCodegen(
@NotNull KtWhenExpression expression,
boolean isStatement,
boolean isExhaustive,
@NotNull ExpressionCodegen codegen
) {
super(expression, isStatement, codegen);
super(expression, isStatement, isExhaustive, codegen);
}
@Override
@@ -35,6 +35,7 @@ import java.util.*;
abstract public class SwitchCodegen {
protected final KtWhenExpression expression;
protected final boolean isStatement;
protected final boolean isExhaustive;
protected final ExpressionCodegen codegen;
protected final BindingContext bindingContext;
protected final Type subjectType;
@@ -49,10 +50,11 @@ abstract public class SwitchCodegen {
public SwitchCodegen(
@NotNull KtWhenExpression expression, boolean isStatement,
@NotNull ExpressionCodegen codegen
boolean isExhaustive, @NotNull ExpressionCodegen codegen
) {
this.expression = expression;
this.isStatement = isStatement;
this.isExhaustive = isExhaustive;
this.codegen = codegen;
this.bindingContext = codegen.getBindingContext();
@@ -70,7 +72,7 @@ abstract public class SwitchCodegen {
boolean hasElse = expression.getElseExpression() != null;
// if there is no else-entry and it's statement then default --- endLabel
defaultLabel = (hasElse || !isStatement) ? elseLabel : endLabel;
defaultLabel = (hasElse || !isStatement || isExhaustive) ? elseLabel : endLabel;
generateSubject();
@@ -79,9 +81,9 @@ abstract public class SwitchCodegen {
generateEntries();
// there is no else-entry but this is not statement, so we should return Unit
if (!hasElse && !isStatement) {
if (!hasElse && (!isStatement || isExhaustive)) {
v.visitLabel(elseLabel);
codegen.putUnitInstanceOntoStackForNonExhaustiveWhen(expression);
codegen.putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement);
}
codegen.markLineNumber(expression, isStatement);
@@ -102,6 +102,7 @@ public class SwitchCodegenUtil {
public static SwitchCodegen buildAppropriateSwitchCodegenIfPossible(
@NotNull KtWhenExpression expression,
boolean isStatement,
boolean isExhaustive,
@NotNull ExpressionCodegen codegen
) {
BindingContext bindingContext = codegen.getBindingContext();
@@ -114,15 +115,15 @@ public class SwitchCodegenUtil {
WhenByEnumsMapping mapping = codegen.getBindingContext().get(CodegenBinding.MAPPING_FOR_WHEN_BY_ENUM, expression);
if (mapping != null) {
return new EnumSwitchCodegen(expression, isStatement, codegen, mapping);
return new EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping);
}
if (isIntegralConstantsSwitch(expression, subjectType, bindingContext)) {
return new IntegralConstantsSwitchCodegen(expression, isStatement, codegen);
return new IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
if (isStringConstantsSwitch(expression, subjectType, bindingContext)) {
return new StringSwitchCodegen(expression, isStatement, codegen);
return new StringSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
return null;