'Else' is not required in 'when' if Unit is expected

This commit is contained in:
Andrey Breslav
2013-09-12 22:04:34 +02:00
parent a76f1c1db5
commit c017858f77
17 changed files with 170 additions and 14 deletions
@@ -837,8 +837,7 @@ public class JetControlFlowProcessor {
}
}
builder.bindLabel(doneLabel);
boolean isWhenExhaust = WhenChecker.isWhenExhaustive(expression, trace);
if (!hasElseOrIrrefutableBranch && !isWhenExhaust) {
if (!hasElseOrIrrefutableBranch && WhenChecker.mustHaveElse(expression, trace)) {
trace.report(NO_ELSE_IN_WHEN.on(expression));
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collection;
@@ -35,7 +36,16 @@ public final class WhenChecker {
private WhenChecker() {
}
public static boolean isWhenExhaustive(@NotNull JetWhenExpression expression, @NotNull BindingTrace trace) {
public static boolean mustHaveElse(@NotNull JetWhenExpression expression, @NotNull BindingTrace trace) {
JetType expectedType = trace.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression);
boolean isUnit = expectedType != null && KotlinBuiltIns.getInstance().isUnit(expectedType);
// Some "statements" are actually expressions returned from lambdas, their expected types are non-null
boolean isStatement = Boolean.TRUE.equals(trace.get(BindingContext.STATEMENT, expression)) && expectedType == null;
return !isUnit && !isStatement && !isWhenExhaustive(expression, trace);
}
private static boolean isWhenExhaustive(@NotNull JetWhenExpression expression, @NotNull BindingTrace trace) {
JetExpression subjectExpression = expression.getSubjectExpression();
if (subjectExpression == null) return false;
JetType type = trace.get(BindingContext.EXPRESSION_TYPE, subjectExpression);
@@ -42,6 +42,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.UNIT_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
public class DataFlowUtils {
@@ -162,9 +163,7 @@ public class DataFlowUtils {
) {
// non-block 'if' branches are wrapped in a block, but here genuine expressions (not wrappers) should be checked
JetExpression expression = JetPsiUtil.unwrapFromBlock(possiblyWrappedInBlockExpression);
if (!noExpectedType(expectedType)) {
trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, expectedType);
}
recordExpectedType(trace, expression, expectedType);
if (expressionType == null || noExpectedType(expectedType) ||
JetTypeChecker.INSTANCE.isSubtypeOf(expressionType, expectedType)) {
@@ -196,6 +195,13 @@ public class DataFlowUtils {
return expressionType;
}
public static void recordExpectedType(@NotNull BindingTrace trace, @NotNull JetExpression expression, @NotNull JetType expectedType) {
if (expectedType != NO_EXPECTED_TYPE) {
JetType normalizeExpectedType = expectedType == UNIT_EXPECTED_TYPE ? KotlinBuiltIns.getInstance().getUnitType() : expectedType;
trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, normalizeExpectedType);
}
}
@NotNull
public static JetTypeInfo checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context, @NotNull DataFlowInfo dataFlowInfo) {
return JetTypeInfo.create(checkStatementType(expression, context), dataFlowInfo);
@@ -66,6 +66,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
}
public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
DataFlowUtils.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
// TODO :change scope according to the bound value in the when header
JetExpression subjectExpression = expression.getSubjectExpression();
@@ -277,7 +279,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (typeReferenceAfterIs == null) {
return noChange(context);
}
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReferenceAfterIs, context.trace, true);
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReferenceAfterIs, context.trace,
true);
if (!subjectType.isNullable() && type.isNullable()) {
JetTypeElement element = typeReferenceAfterIs.getTypeElement();
assert element instanceof JetNullableType : "element must be instance of " + JetNullableType.class.getName();