From 78a526c9377c21457f391befffb354963355a72f Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Tue, 21 Nov 2017 18:58:37 +0300 Subject: [PATCH] [NI] Support EffectSystem - During final phase of resolution (i.e. converting NI-results to OI-results), make call into EffectSystem to record all necessary effects-related information. - To be able to enhance resulting dataFlowInfo for call at that stage, introduce internal method 'updateResultingDataFlowInfo' in NewResolvedCallImpl. --- .../tower/KotlinToResolvedCallTransformer.kt | 18 ++++++++-- .../resolve/calls/tower/PSICallResolver.kt | 35 ++++++++++++++----- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index b76ace907c2..382c3bb9bd3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.contracts.EffectSystem import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors @@ -68,7 +69,8 @@ class KotlinToResolvedCallTransformer( private val deprecationResolver: DeprecationResolver, private val expressionTypingServices: ExpressionTypingServices, private val doubleColonExpressionResolver: DoubleColonExpressionResolver, - private val additionalDiagnosticReporter: AdditionalDiagnosticReporter + private val additionalDiagnosticReporter: AdditionalDiagnosticReporter, + private val effectSystem: EffectSystem ) { companion object { @@ -387,6 +389,8 @@ sealed class NewAbstractResolvedCall(): ResolvedCall protected var argumentToParameterMap: Map? = null protected var _valueArguments: Map? = null + private var nonTrivialUpdatedResultInfo: DataFlowInfo? = null + override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall override fun getValueArguments(): Map { @@ -423,7 +427,8 @@ sealed class NewAbstractResolvedCall(): ResolvedCall } override fun getDataFlowInfoForArguments() = object : DataFlowInfoForArguments { - override fun getResultInfo() = kotlinCall.psiKotlinCall.resultDataFlowInfo + override fun getResultInfo(): DataFlowInfo = nonTrivialUpdatedResultInfo ?: kotlinCall.psiKotlinCall.resultDataFlowInfo + override fun getInfo(valueArgument: ValueArgument): DataFlowInfo { val externalPsiCallArgument = kotlinCall.externalArgument?.psiCallArgument if (externalPsiCallArgument?.valueArgument == valueArgument) { @@ -433,6 +438,15 @@ sealed class NewAbstractResolvedCall(): ResolvedCall } } + // Currently, updated only with info from effect system + internal fun updateResultingDataFlowInfo(dataFlowInfo: DataFlowInfo) { + if (dataFlowInfo == DataFlowInfo.EMPTY) return + assert(nonTrivialUpdatedResultInfo == null) { + "Attempt to rewrite resulting dataFlowInfo enhancement for call: $kotlinCall" + } + nonTrivialUpdatedResultInfo = dataFlowInfo.and(kotlinCall.psiKotlinCall.resultDataFlowInfo) + } + private fun argumentToParameterMap( resultingDescriptor: CallableDescriptor, valueArguments: Map diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index d465277eaed..e5251072737 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -18,20 +18,15 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.contracts.EffectSystem +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.referenceExpression -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.ModifierCheckerCore -import org.jetbrains.kotlin.resolve.TemporaryBindingTrace -import org.jetbrains.kotlin.resolve.TypeResolver +import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator @@ -73,7 +68,8 @@ class PSICallResolver( private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, private val kotlinCallResolver: KotlinCallResolver, private val typeApproximator: TypeApproximator, - private val argumentTypeResolver: ArgumentTypeResolver + private val argumentTypeResolver: ArgumentTypeResolver, + private val effectSystem: EffectSystem ) { private val GIVEN_CANDIDATES_NAME = Name.special("") @@ -221,9 +217,30 @@ class PSICallResolver( else { kotlinToResolvedCallTransformer.transformAndReport(result, context) } + + // NB. Be careful with moving this invocation, as effect system expects resolution results to be written in trace + // (see EffectSystem for details) + resolvedCall.recordEffects(trace) + return SingleOverloadResolutionResult(resolvedCall) } + private fun ResolvedCall<*>.recordEffects(trace: BindingTrace) { + val moduleDescriptor = DescriptorUtils.getContainingModule(this.resultingDescriptor?.containingDeclaration ?: return) + recordLambdasInvocations(trace, moduleDescriptor) + recordResultInfo(trace, moduleDescriptor) + } + + private fun ResolvedCall<*>.recordResultInfo(trace: BindingTrace, moduleDescriptor: ModuleDescriptor) { + if (this !is NewResolvedCallImpl) return + val resultDFIfromES = effectSystem.getDataFlowInfoForFinishedCall(this, trace, moduleDescriptor) + this.updateResultingDataFlowInfo(resultDFIfromES) + } + + private fun ResolvedCall<*>.recordLambdasInvocations(trace: BindingTrace, moduleDescriptor: ModuleDescriptor) { + effectSystem.recordDefiniteInvocations(this, trace, moduleDescriptor) + } + private fun CallResolutionResult.isEmpty(): Boolean = diagnostics.firstIsInstanceOrNull() != null