Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
import org.jetbrains.kotlin.resolve.calls.context.*
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.*
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
import org.jetbrains.kotlin.resolve.isHiddenInResolution
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.DeferredType
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.sure
import java.lang.IllegalStateException
import java.util.*
class NewResolutionOldInference(
private val candidateResolver: CandidateResolver,
private val towerResolver: TowerResolver,
private val resolutionResultsHandler: ResolutionResultsHandler,
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
private val syntheticScopes: SyntheticScopes,
private val languageVersionSettings: LanguageVersionSettings,
private val coroutineInferenceSupport: CoroutineInferenceSupport
) {
sealed class ResolutionKind {
abstract internal fun createTowerProcessor(
outer: NewResolutionOldInference,
name: Name,
tracing: TracingStrategy,
scopeTower: ImplicitScopeTower,
explicitReceiver: DetailedReceiver?,
context: BasicCallResolutionContext
): ScopeTowerProcessor
object Function : ResolutionKind() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
return createFunctionProcessor(scopeTower, name, functionFactory, outer.CandidateFactoryProviderForInvokeImpl(functionFactory), explicitReceiver)
}
}
object Variable : ResolutionKind() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor {
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
return createVariableAndObjectProcessor(scopeTower, name, variableFactory, explicitReceiver)
}
}
object CallableReference : ResolutionKind() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
return CompositeScopeTowerProcessor(
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
)
}
}
object Invoke : ResolutionKind() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
// todo
val call = (context.call as? CallTransformer.CallForImplicitInvoke).sure {
"Call should be CallForImplicitInvoke, but it is: ${context.call}"
}
return createProcessorWithReceiverValueOrEmpty(explicitReceiver) {
createCallTowerProcessorForExplicitInvoke(scopeTower, functionFactory, context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver), it)
}
}
}
class GivenCandidates : ResolutionKind() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor {
throw IllegalStateException("Should be not called")
}
}
}
fun runResolution(
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind,
tracing: TracingStrategy
): OverloadResolutionResultsImpl {
val explicitReceiver = context.call.explicitReceiver
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
explicitReceiver
}
else {
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
}
val dynamicScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
val scopeTower = ImplicitScopeTowerImpl(context, dynamicScope, syntheticScopes, context.call.createLookupLocation())
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
val isBinaryRemOperator = isBinaryRemOperator(context.call)
val nameToResolve = if (isBinaryRemOperator && !shouldUseOperatorRem)
OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]!!
else
name
val processor = kind.createTowerProcessor(this, nameToResolve, tracing, scopeTower, detailedReceiver, context)
if (context.collectAllCandidates) {
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor))
}
var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference)
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
candidates.all {
it.candidateStatus.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE
}
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference)
}
if (candidates.isEmpty()) {
if (reportAdditionalDiagnosticIfNoCandidates(context, nameToResolve, kind, scopeTower, detailedReceiver)) {
return OverloadResolutionResultsImpl.nameNotFound()
}
}
val overloadResults = convertToOverloadResults(candidates, tracing, context, languageVersionSettings)
coroutineInferenceSupport.checkCoroutineCalls(context, tracing, overloadResults)
return overloadResults
}
fun runResolutionForGivenCandidates(
basicCallContext: BasicCallResolutionContext,
tracing: TracingStrategy,
candidates: Collection>
): OverloadResolutionResultsImpl {
val resolvedCandidates = candidates.map { candidate ->
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
if (candidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
return@map MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), resolvedCall)
}
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.FULLY // todo
)
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
MyCandidate(ResolutionCandidateStatus(diagnostics), resolvedCall)
}
if (basicCallContext.collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.AllCandidatesCollector { it.candidateStatus }, useOrder = false)
return allCandidatesResult(allCandidates)
}
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.SuccessfulResultCollector { it.candidateStatus }, useOrder = true)
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
}
private fun allCandidatesResult(allCandidates: Collection)
= OverloadResolutionResultsImpl.nameNotFound().apply {
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall }
}
private fun convertToOverloadResults(
candidates: Collection,
tracing: TracingStrategy,
basicCallContext: BasicCallResolutionContext,
languageVersionSettings: LanguageVersionSettings
): OverloadResolutionResultsImpl {
val resolvedCalls = candidates.map {
val (status, resolvedCall) = it
if (resolvedCall is VariableAsFunctionResolvedCallImpl) {
// todo hacks
tracing.bindReference(resolvedCall.variableCall.trace, resolvedCall.variableCall)
tracing.bindResolvedCall(resolvedCall.variableCall.trace, resolvedCall)
resolvedCall.variableCall.trace.addOwnDataTo(resolvedCall.functionCall.trace)
resolvedCall.functionCall.tracingStrategy.bindReference(resolvedCall.functionCall.trace, resolvedCall.functionCall)
// resolvedCall.hackInvokeTracing.bindResolvedCall(resolvedCall.functionCall.trace, resolvedCall)
} else {
tracing.bindReference(resolvedCall.trace, resolvedCall)
tracing.bindResolvedCall(resolvedCall.trace, resolvedCall)
}
if (resolvedCall.status.possibleTransformToSuccess()) {
for (error in status.diagnostics) {
when (error) {
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
is ErrorDescriptorDiagnostic -> {
// todo
// return@map null
}
}
}
}
resolvedCall as MutableResolvedCall
}
return resolutionResultsHandler.computeResultAndReportErrors(basicCallContext, tracing, resolvedCalls, languageVersionSettings)
}
// true if we found something
private fun reportAdditionalDiagnosticIfNoCandidates(
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind<*>,
scopeTower: ImplicitScopeTower,
detailedReceiver: DetailedReceiver?
): Boolean {
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
val errorCandidates = when (kind) {
ResolutionKind.Function -> collectErrorCandidatesForFunction(scopeTower, name, detailedReceiver)
ResolutionKind.Variable -> collectErrorCandidatesForVariable(scopeTower, name, detailedReceiver)
else -> emptyList()
}
val candidate = errorCandidates.firstOrNull() as? ErrorCandidate.Classifier ?: return false
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor)
context.trace.report(Errors.RESOLUTION_TO_CLASSIFIER.on(reference, candidate.descriptor, candidate.kind, candidate.errorMessage))
return true
}
private class ImplicitScopeTowerImpl(
val resolutionContext: ResolutionContext<*>,
override val dynamicScope: MemberScope,
override val syntheticScopes: SyntheticScopes,
override val location: LookupLocation
): ImplicitScopeTower {
private val cache = HashMap()
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? =
scope.implicitReceiver?.value?.let {
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
}
override val lexicalScope: LexicalScope get() = resolutionContext.scope
override val isDebuggerContext: Boolean get() = resolutionContext.isDebuggerContext
}
internal data class MyCandidate(
val candidateStatus: ResolutionCandidateStatus,
val resolvedCall: MutableResolvedCall<*>
) : Candidate {
override val isSuccessful: Boolean
get() = candidateStatus.resultingApplicability.isSuccess
override val status: ResolutionCandidateStatus
get() = candidateStatus
}
private inner class CandidateFactoryImpl(
val name: Name,
val basicCallContext: BasicCallResolutionContext,
val tracing: TracingStrategy
) : CandidateFactory {
override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): MyCandidate {
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
val candidateCall = ResolvedCallImpl(
basicCallContext.call, towerCandidate.descriptor,
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
explicitReceiverKind, null, candidateTrace, tracing,
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
)
/**
* See https://jetbrains.quip.com/qcTDAFcgFLEM
*
* For now we have only 2 functions with dynamic receivers: iterator() and unsafeCast()
* Both this function are marked via @kotlin.internal.DynamicExtension.
*/
if (extensionReceiver != null) {
val parameterIsDynamic = towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()
val argumentIsDynamic = extensionReceiver.receiverValue.type.isDynamic()
if (parameterIsDynamic != argumentIsDynamic ||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())
) {
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenExtensionRelatedToDynamicTypes)), candidateCall)
}
}
if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), candidateCall)
}
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.FULLY // todo
)
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
val diagnostics = (towerCandidate.diagnostics +
checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) +
createPreviousResolveError(candidateCall.status)).filterNotNull() // todo
return MyCandidate(ResolutionCandidateStatus(diagnostics), candidateCall)
}
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List {
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
if (descriptor.name != name && (name == OperatorNameConventions.UNARY_PLUS || name == OperatorNameConventions.UNARY_MINUS)) {
return listOf(DeprecatedUnaryPlusAsPlus)
}
val conventionError = if (isConventionCall(call) && !descriptor.isOperator) InvokeConventionCallNoOperatorModifier else null
val infixError = if (isInfixCall(call) && !descriptor.isInfix) InfixCallNoInfixModifier else null
return listOfNotNull(conventionError, infixError)
}
}
private inner class CandidateFactoryProviderForInvokeImpl(
val functionContext: CandidateFactoryImpl
) : CandidateFactoryProviderForInvoke {
override fun transformCandidate(
variable: MyCandidate,
invoke: MyCandidate
): MyCandidate {
val resolvedCallImpl = VariableAsFunctionResolvedCallImpl(
invoke.resolvedCall as MutableResolvedCall,
variable.resolvedCall as MutableResolvedCall
)
assert(variable.candidateStatus.resultingApplicability.isSuccess) {
"Variable call must be success: $variable"
}
return MyCandidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl)
}
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory {
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it
}
return CandidateFactoryImpl(functionContext.name, functionContext.basicCallContext.replaceCall(newCall), functionContext.tracing)
}
override fun factoryForInvoke(
variable: MyCandidate,
useExplicitReceiver: Boolean
): Pair>? {
assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
}
val calleeExpression = variable.resolvedCall.call.calleeExpression
val variableDescriptor = variable.resolvedCall.resultingDescriptor as VariableDescriptor
assert(variable.resolvedCall.status.possibleTransformToSuccess() && calleeExpression != null) {
"Unexpected variable candidate: $variable"
}
val variableType = variableDescriptor.type
if (variableType is DeferredType && variableType.isComputing) {
return null // todo: create special check that there is no invoke on variable
}
val basicCallContext = functionContext.basicCallContext
val variableReceiver = ExpressionReceiver.create(calleeExpression!!,
variableType,
basicCallContext.trace.bindingContext)
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
// todo hacks
val functionCall = CallTransformer.CallForImplicitInvoke(
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
variableReceiver, basicCallContext.call, true)
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
.replaceCall(functionCall)
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
val newContext = CandidateFactoryImpl(OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke)
return basicCallResolutionContext.transformToReceiverWithSmartCastInfo(variableReceiver) to newContext
}
}
}
private fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue): ReceiverValueWithSmartCastInfo {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, this)
return ReceiverValueWithSmartCastInfo(receiver, dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
}
@Deprecated("Temporary error")
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability): ResolutionDiagnostic(candidateLevel)
@Deprecated("Temporary error")
internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? {
val level = when (status) {
ResolutionStatus.SUCCESS, ResolutionStatus.INCOMPLETE_TYPE_INFERENCE -> return null
ResolutionStatus.UNSAFE_CALL_ERROR -> ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR
else -> ResolutionCandidateApplicability.INAPPLICABLE
}
return PreviousResolutionError(level)
}
private val BasicCallResolutionContext.isSuperCall: Boolean get() = call.explicitReceiver is SuperCallReceiverValue