From 26cc08be65c918b528ee480f96ed3d98e9cc4ee1 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 7 Jun 2017 13:06:45 +0300 Subject: [PATCH] Fix anonymous function literals handling in type checker - [NI] Create type info directly if the expected type is functional. - Properly handle suspended function expected type. --- .../expressions/FunctionsTypingVisitor.kt | 30 ++++++++++++++----- .../lambdaInValInitializer.kt | 5 ++++ .../lambdaInValInitializer.txt | 4 +++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index e956879ac34..f58156fbe62 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -123,7 +123,17 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context) } else { - components.dataFlowAnalyzer.createCheckedTypeInfo(functionDescriptor.createFunctionType(), context, function) + val expectedType = context.expectedType + + val functionalTypeExpected = expectedType.isBuiltinFunctionalType() + val suspendFunctionTypeExpected = expectedType.isSuspendFunctionType() + + val resultType = functionDescriptor.createFunctionType(suspendFunctionTypeExpected) + + if (functionalTypeExpected) + createTypeInfo(resultType, context) + else + components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, function) } } @@ -144,8 +154,8 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre if (!expression.functionLiteral.hasBody()) return null val expectedType = context.expectedType - val functionTypeExpected = !noExpectedType(expectedType) && expectedType.isBuiltinFunctionalType - val suspendFunctionTypeExpected = !noExpectedType(expectedType) && expectedType.isSuspendFunctionType + val functionTypeExpected = expectedType.isBuiltinFunctionalType() + val suspendFunctionTypeExpected = expectedType.isSuspendFunctionType() val functionDescriptor = createFunctionLiteralDescriptor(expression, context) expression.valueParameters.forEach { @@ -174,10 +184,10 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre ): AnonymousFunctionDescriptor { val functionLiteral = expression.functionLiteral val functionDescriptor = AnonymousFunctionDescriptor( - context.scope.ownerDescriptor, - components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace), - CallableMemberDescriptor.Kind.DECLARATION, functionLiteral.toSourceElement(), - !noExpectedType(context.expectedType) && context.expectedType.isSuspendFunctionType + context.scope.ownerDescriptor, + components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace), + CallableMemberDescriptor.Kind.DECLARATION, functionLiteral.toSourceElement(), + context.expectedType.isSuspendFunctionType() ) components.functionDescriptorResolver. initializeFunctionDescriptorAndExplicitReturnType(context.scope.ownerDescriptor, context.scope, functionLiteral, @@ -189,6 +199,12 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre return functionDescriptor } + private fun KotlinType.isBuiltinFunctionalType() = + !noExpectedType(this) && isBuiltinFunctionalType + + private fun KotlinType.isSuspendFunctionType() = + !noExpectedType(this) && isSuspendFunctionType + private fun computeReturnType( expression: KtLambdaExpression, context: ExpressionTypingContext, diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.kt index d54b82ca84d..b4a37af6028 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.kt @@ -4,3 +4,8 @@ val test1: suspend () -> Unit = {} val test2: suspend Any.() -> Unit = {} val test3: suspend Any.(Int) -> Int = { k: Int -> k + 1 } val test4: SuspendFn = {} + +val test1f: suspend () -> Unit = fun () {} +val test2f: suspend Any.() -> Unit = fun Any.() {} +val test3f: suspend Any.(Int) -> Int = fun (k: Int) = k + 1 +val test4f: SuspendFn = fun Any.() {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.txt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.txt index b16b1d8303d..b2e8169f135 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/lambdaInValInitializer.txt @@ -1,7 +1,11 @@ package public val test1: suspend () -> kotlin.Unit +public val test1f: suspend () -> kotlin.Unit public val test2: suspend kotlin.Any.() -> kotlin.Unit +public val test2f: suspend kotlin.Any.() -> kotlin.Unit public val test3: suspend kotlin.Any.(kotlin.Int) -> kotlin.Int +public val test3f: suspend kotlin.Any.(kotlin.Int) -> kotlin.Int public val test4: SuspendFn /* = suspend () -> kotlin.Unit */ +public val test4f: SuspendFn /* = suspend () -> kotlin.Unit */ public typealias SuspendFn = suspend () -> kotlin.Unit