[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.
This commit is contained in:
Dmitry Savvinov
2017-11-21 18:58:37 +03:00
parent b23d62c760
commit 78a526c937
2 changed files with 42 additions and 11 deletions
@@ -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<D : CallableDescriptor>(): ResolvedCall<D>
protected var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
protected var _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>? = null
private var nonTrivialUpdatedResultInfo: DataFlowInfo? = null
override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall
override fun getValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> {
@@ -423,7 +427,8 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
}
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<D : CallableDescriptor>(): ResolvedCall<D>
}
}
// 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<ValueParameterDescriptor, ResolvedValueArgument>
@@ -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("<given candidates>")
@@ -221,9 +217,30 @@ class PSICallResolver(
else {
kotlinToResolvedCallTransformer.transformAndReport<D>(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<NoneCandidatesCallDiagnostic>() != null