Fix KT-10775 Empty when causes compilation exception.

Expression type for an empty 'when' is 'kotlin.Unit'.
This commit is contained in:
Dmitry Petrov
2016-01-29 14:34:38 +03:00
parent dcc6262f47
commit b3f390abe5
3 changed files with 27 additions and 14 deletions
@@ -19,13 +19,11 @@ package org.jetbrains.kotlin.types.expressions
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean
import org.jetbrains.kotlin.cfg.WhenChecker import org.jetbrains.kotlin.cfg.WhenChecker
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
@@ -81,9 +79,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType) checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType)
val resolvedCall = resolveSpecialCallForWhen(expression, contextWithExpectedType, contextAfterSubject, subjectDataFlowValue, subjectType) val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType)
val whenReturnType = inferTypeForWhenExpression(expression, contextWithExpectedType, contextAfterSubject, dataFlowInfoForEntries)
val whenReturnType = resolvedCall.resultingDescriptor.returnType
val whenResultValue = whenReturnType?.let { DataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) } val whenResultValue = whenReturnType?.let { DataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) }
val (outputDataFlowInfo, jumpOutPossible) = val (outputDataFlowInfo, jumpOutPossible) =
@@ -111,20 +108,21 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
return createTypeInfo(resultType, resultDataFlowInfo, jumpOutPossible, contextWithExpectedType.dataFlowInfo) return createTypeInfo(resultType, resultDataFlowInfo, jumpOutPossible, contextWithExpectedType.dataFlowInfo)
} }
private fun resolveSpecialCallForWhen( private fun inferTypeForWhenExpression(
expression: KtWhenExpression, expression: KtWhenExpression,
contextWithExpectedType: ExpressionTypingContext, contextWithExpectedType: ExpressionTypingContext,
contextAfterSubject: ExpressionTypingContext, contextAfterSubject: ExpressionTypingContext,
subjectDataFlowValue: DataFlowValue, dataFlowInfoForEntries: List<DataFlowInfo>
subjectType: KotlinType ): KotlinType? {
): ResolvedCall<FunctionDescriptor> { if (expression.entries.all { it.expression == null }) {
return components.builtIns.unitType
}
val wrappedArgumentExpressions = wrapWhenEntryExpressionsAsSpecialCallArguments(expression) val wrappedArgumentExpressions = wrapWhenEntryExpressionsAsSpecialCallArguments(expression)
val argumentDataFlowInfos = collectInputDataFlowForWhenEntryExpressions(expression, contextAfterSubject, subjectDataFlowValue, subjectType)
val callForWhen = createCallForSpecialConstruction(expression, expression, wrappedArgumentExpressions) val callForWhen = createCallForSpecialConstruction(expression, expression, wrappedArgumentExpressions)
val dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfWhenCall(callForWhen, contextAfterSubject.dataFlowInfo, argumentDataFlowInfos) val dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfWhenCall(callForWhen, contextAfterSubject.dataFlowInfo, dataFlowInfoForEntries)
return components.controlStructureTypingUtils.resolveSpecialConstructionAsCall( val resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
callForWhen, ResolveConstruct.WHEN, callForWhen, ResolveConstruct.WHEN,
object : AbstractList<String>() { object : AbstractList<String>() {
override fun get(index: Int): String = "entry$index" override fun get(index: Int): String = "entry$index"
@@ -132,6 +130,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
}, },
Collections.nCopies(wrappedArgumentExpressions.size, false), Collections.nCopies(wrappedArgumentExpressions.size, false),
contextWithExpectedType, dataFlowInfoForArguments) contextWithExpectedType, dataFlowInfoForArguments)
return resolvedCall.resultingDescriptor.returnType
} }
private fun wrapWhenEntryExpressionsAsSpecialCallArguments(expression: KtWhenExpression): List<KtExpression> { private fun wrapWhenEntryExpressionsAsSpecialCallArguments(expression: KtWhenExpression): List<KtExpression> {
@@ -142,7 +142,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
return wrappedArgumentExpressions return wrappedArgumentExpressions
} }
private fun collectInputDataFlowForWhenEntryExpressions( private fun analyzeConditionsInWhenEntries(
expression: KtWhenExpression, expression: KtWhenExpression,
contextAfterSubject: ExpressionTypingContext, contextAfterSubject: ExpressionTypingContext,
subjectDataFlowValue: DataFlowValue, subjectDataFlowValue: DataFlowValue,
+7
View File
@@ -0,0 +1,7 @@
enum class A { X1, X2 }
fun box(): String {
when {}
when (A.X1) {}
return "OK"
}
@@ -8287,6 +8287,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("emptyWhen.kt")
public void testEmptyWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/emptyWhen.kt");
doTest(fileName);
}
@TestMetadata("exhaustiveBoolean.kt") @TestMetadata("exhaustiveBoolean.kt")
public void testExhaustiveBoolean() throws Exception { public void testExhaustiveBoolean() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/exhaustiveBoolean.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/exhaustiveBoolean.kt");