From b3f390abe5acf5fa64815c428243de904a52f1ca Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 29 Jan 2016 14:34:38 +0300 Subject: [PATCH] Fix KT-10775 Empty when causes compilation exception. Expression type for an empty 'when' is 'kotlin.Unit'. --- .../PatternMatchingTypingVisitor.kt | 28 +++++++++---------- .../testData/codegen/box/when/emptyWhen.kt | 7 +++++ .../BlackBoxCodegenTestGenerated.java | 6 ++++ 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/box/when/emptyWhen.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index add3bd1ddff..25d79630623 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -19,13 +19,11 @@ package org.jetbrains.kotlin.types.expressions import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean 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.psi.* import org.jetbrains.kotlin.resolve.* 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.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory @@ -81,9 +79,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType) - val resolvedCall = resolveSpecialCallForWhen(expression, contextWithExpectedType, contextAfterSubject, subjectDataFlowValue, subjectType) - - val whenReturnType = resolvedCall.resultingDescriptor.returnType + val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType) + val whenReturnType = inferTypeForWhenExpression(expression, contextWithExpectedType, contextAfterSubject, dataFlowInfoForEntries) val whenResultValue = whenReturnType?.let { DataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) } val (outputDataFlowInfo, jumpOutPossible) = @@ -111,20 +108,21 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping return createTypeInfo(resultType, resultDataFlowInfo, jumpOutPossible, contextWithExpectedType.dataFlowInfo) } - private fun resolveSpecialCallForWhen( + private fun inferTypeForWhenExpression( expression: KtWhenExpression, contextWithExpectedType: ExpressionTypingContext, contextAfterSubject: ExpressionTypingContext, - subjectDataFlowValue: DataFlowValue, - subjectType: KotlinType - ): ResolvedCall { + dataFlowInfoForEntries: List + ): KotlinType? { + if (expression.entries.all { it.expression == null }) { + return components.builtIns.unitType + } + val wrappedArgumentExpressions = wrapWhenEntryExpressionsAsSpecialCallArguments(expression) - val argumentDataFlowInfos = collectInputDataFlowForWhenEntryExpressions(expression, contextAfterSubject, subjectDataFlowValue, subjectType) - 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, object : AbstractList() { override fun get(index: Int): String = "entry$index" @@ -132,6 +130,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping }, Collections.nCopies(wrappedArgumentExpressions.size, false), contextWithExpectedType, dataFlowInfoForArguments) + + return resolvedCall.resultingDescriptor.returnType } private fun wrapWhenEntryExpressionsAsSpecialCallArguments(expression: KtWhenExpression): List { @@ -142,7 +142,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping return wrappedArgumentExpressions } - private fun collectInputDataFlowForWhenEntryExpressions( + private fun analyzeConditionsInWhenEntries( expression: KtWhenExpression, contextAfterSubject: ExpressionTypingContext, subjectDataFlowValue: DataFlowValue, diff --git a/compiler/testData/codegen/box/when/emptyWhen.kt b/compiler/testData/codegen/box/when/emptyWhen.kt new file mode 100644 index 00000000000..62ab58b6bf3 --- /dev/null +++ b/compiler/testData/codegen/box/when/emptyWhen.kt @@ -0,0 +1,7 @@ +enum class A { X1, X2 } + +fun box(): String { + when {} + when (A.X1) {} + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index d9f6ede4f22..e01b2e5bc67 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -8287,6 +8287,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { 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") public void testExhaustiveBoolean() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/when/exhaustiveBoolean.kt");