From 87b0bc43d5667037946467f9562ee204906a78bf Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Tue, 3 Oct 2017 15:02:38 +0300 Subject: [PATCH] Effects: support parsing of functions contracts Make a fastcheck for a presence of contract-declaration in function body of FunctionDescriptorResolver. If there's something that looks like contract and we need resolve to make a final decision, then prepare LazyContractProvider key in UserDataMap of function's descriptor. Note that we can't passively wait with contracts resolving until the function body is analyzed, because we may need it earlier. However, we can't force body resolve straight during descriptors resolving, because we can run into recursive problems. That's why we are saving deferred resolving of functions body via LazyContractProvider. Also, we have to pass DataFlowInfo into initializeFunctionDescriptorAndExplicitReturnType, because we save deferred body resolving inside, which needs DataFlowInfo. ========== Effect System introduction: 9/18 --- .../resolve/FunctionDescriptorResolver.kt | 44 ++++++++++++++++--- .../expressions/FunctionsTypingVisitor.kt | 2 +- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt index 7a1ac3ef704..f3d3ed06329 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt @@ -21,6 +21,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType +import org.jetbrains.kotlin.config.AnalysisFlag +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.contracts.description.ContractProviderKey +import org.jetbrains.kotlin.contracts.description.LazyContractProvider +import org.jetbrains.kotlin.contracts.parsing.ContractParsingServices import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl @@ -33,8 +39,8 @@ import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultModality import org.jetbrains.kotlin.resolve.DescriptorResolver.getDefaultVisibility import org.jetbrains.kotlin.resolve.DescriptorUtils.getDispatchReceiverParameterIfNeeded @@ -53,6 +59,7 @@ import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral @@ -65,7 +72,10 @@ class FunctionDescriptorResolver( private val annotationResolver: AnnotationResolver, private val builtIns: KotlinBuiltIns, private val modifiersChecker: ModifiersChecker, - private val overloadChecker: OverloadChecker + private val overloadChecker: OverloadChecker, + private val contractParsingServices: ContractParsingServices, + private val expressionTypingServices: ExpressionTypingServices, + private val languageVersionSettings: LanguageVersionSettings ) { fun resolveFunctionDescriptor( containingDescriptor: DeclarationDescriptor, @@ -107,7 +117,7 @@ class FunctionDescriptorResolver( CallableMemberDescriptor.Kind.DECLARATION, function.toSourceElement() ) - initializeFunctionDescriptorAndExplicitReturnType(containingDescriptor, scope, function, functionDescriptor, trace, expectedFunctionType) + initializeFunctionDescriptorAndExplicitReturnType(containingDescriptor, scope, function, functionDescriptor, trace, expectedFunctionType, dataFlowInfo) initializeFunctionReturnTypeBasedOnFunctionBody(scope, function, functionDescriptor, trace, dataFlowInfo) BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, function, functionDescriptor) return functionDescriptor @@ -141,7 +151,8 @@ class FunctionDescriptorResolver( function: KtFunction, functionDescriptor: SimpleFunctionDescriptorImpl, trace: BindingTrace, - expectedFunctionType: KotlinType + expectedFunctionType: KotlinType, + dataFlowInfo: DataFlowInfo ) { val headerScope = LexicalWritableScope(scope, functionDescriptor, true, TraceBasedLocalRedeclarationChecker(trace, overloadChecker), LexicalScopeKind.FUNCTION_HEADER) @@ -169,6 +180,8 @@ class FunctionDescriptorResolver( val visibility = resolveVisibilityFromModifiers(function, getDefaultVisibility(function, container)) val modality = resolveMemberModalityFromModifiers(function, getDefaultModality(container, visibility, function.hasBody()), trace.bindingContext, container) + val contractProvider = getContractProvider(functionDescriptor, trace, scope, dataFlowInfo, function) + functionDescriptor.initialize( receiverType, getDispatchReceiverParameterIfNeeded(container), @@ -176,7 +189,8 @@ class FunctionDescriptorResolver( valueParameterDescriptors, returnType, modality, - visibility + visibility, + mapOf(ContractProviderKey to contractProvider) ) functionDescriptor.isOperator = function.hasModifier(KtTokens.OPERATOR_KEYWORD) functionDescriptor.isInfix = function.hasModifier(KtTokens.INFIX_KEYWORD) @@ -194,6 +208,26 @@ class FunctionDescriptorResolver( } } + private fun getContractProvider( + functionDescriptor: SimpleFunctionDescriptorImpl, + trace: BindingTrace, + scope: LexicalScope, + dataFlowInfo: DataFlowInfo, + function: KtFunction + ): LazyContractProvider { + val provideByDeferredForceResolve = LazyContractProvider { + expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor) + } + val emptyContract = LazyContractProvider.createInitialized(null) + + val isContractsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) || + languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) + + if (!isContractsEnabled || !contractParsingServices.fastCheckIfContractPresent(function)) return emptyContract + + return provideByDeferredForceResolve + } + private fun createValueParameterDescriptors( function: KtFunction, functionDescriptor: SimpleFunctionDescriptorImpl, 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 12b21e66ea2..3936ca7220e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -193,7 +193,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre ) components.functionDescriptorResolver. initializeFunctionDescriptorAndExplicitReturnType(context.scope.ownerDescriptor, context.scope, functionLiteral, - functionDescriptor, context.trace, context.expectedType) + functionDescriptor, context.trace, context.expectedType, context.dataFlowInfo) for (parameterDescriptor in functionDescriptor.valueParameters) { ForceResolveUtil.forceResolveAllContents(parameterDescriptor.annotations) }