Fix KT-10775 Empty when causes compilation exception.
Expression type for an empty 'when' is 'kotlin.Unit'.
This commit is contained in:
+14
-14
@@ -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,
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
enum class A { X1, X2 }
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
when {}
|
||||||
|
when (A.X1) {}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+6
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user