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
This commit is contained in:
Dmitry Savvinov
2017-10-03 15:02:38 +03:00
parent 175d23155e
commit 87b0bc43d5
2 changed files with 40 additions and 6 deletions
@@ -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,
@@ -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)
}