/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.resolve.calls.components.*
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.DelegatedPropertyConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallComponents
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaAtom
import org.jetbrains.kotlin.resolve.calls.tower.ManyCandidatesResolver
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver
import org.jetbrains.kotlin.resolve.calls.tower.PSIPartialCallInfo
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.util.OperatorNameConventions
class DelegatedPropertyInferenceSession(
val variableDescriptor: VariableDescriptorWithAccessors,
val expectedType: UnwrappedType?,
psiCallResolver: PSICallResolver,
postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter,
callComponents: KotlinCallComponents,
builtIns: KotlinBuiltIns
) : ManyCandidatesResolver<FunctionDescriptor>(
psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns
) {
override fun prepareForCompletion(commonSystem: NewConstraintSystem, resolvedCallsInfo: List<PSIPartialCallInfo>) {
val csBuilder = commonSystem.getBuilder()
for (callInfo in resolvedCallsInfo) {
val resultAtom = callInfo.callResolutionResult.resultCallAtom
when (resultAtom.candidateDescriptor.name) {
OperatorNameConventions.GET_VALUE -> resultAtom.addConstraintsForGetValueMethod(csBuilder)
OperatorNameConventions.SET_VALUE -> resultAtom.addConstraintsForSetValueMethod(csBuilder)
}
}
}
private fun ResolvedCallAtom.addConstraintForThis(descriptor: CallableDescriptor, commonSystem: ConstraintSystemBuilder) {
val typeOfThis = variableDescriptor.extensionReceiverParameter?.type
?: variableDescriptor.dispatchReceiverParameter?.type
?: builtIns.nullableNothingType
val valueParameterForThis = descriptor.valueParameters.getOrNull(0) ?: return
val substitutedType = substitutor.substituteKeepAnnotations(valueParameterForThis.type.unwrap())
commonSystem.addSubtypeConstraint(typeOfThis.unwrap(), substitutedType, DelegatedPropertyConstraintPosition(atom))
}
private fun ResolvedCallAtom.addConstraintsForGetValueMethod(commonSystem: ConstraintSystemBuilder) {
if (expectedType != null) {
val unsubstitutedReturnType = candidateDescriptor.returnType?.unwrap() ?: return
val substitutedReturnType = substitutor.substituteKeepAnnotations(unsubstitutedReturnType)
commonSystem.addSubtypeConstraint(substitutedReturnType, expectedType, DelegatedPropertyConstraintPosition(atom))
}
addConstraintForThis(candidateDescriptor, commonSystem)
}
private fun ResolvedCallAtom.addConstraintsForSetValueMethod(commonSystem: ConstraintSystemBuilder) {
if (expectedType != null) {
val unsubstitutedParameterType = candidateDescriptor.valueParameters.getOrNull(2)?.type?.unwrap() ?: return
val substitutedParameterType = substitutor.substituteKeepAnnotations(unsubstitutedParameterType)
commonSystem.addSubtypeConstraint(expectedType, substitutedParameterType, DelegatedPropertyConstraintPosition(atom))
}
addConstraintForThis(candidateDescriptor, commonSystem)
}
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
initialStorage: ConstraintStorage
): Map<TypeConstructor, UnwrappedType> = emptyMap()
override fun writeOnlyStubs(): Boolean = false
}
object InferenceSessionForExistingCandidates : InferenceSession {
override fun shouldRunCompletion(candidate: KotlinResolutionCandidate): Boolean {
return !ErrorUtils.isError(candidate.resolvedCall.candidateDescriptor)
}
override fun addPartialCallInfo(callInfo: PartialCallInfo) {}
override fun addCompletedCallInfo(callInfo: CompletedCallInfo) {}
override fun addErrorCallInfo(callInfo: ErrorCallInfo) {}
override fun currentConstraintSystem(): ConstraintStorage = ConstraintStorage.Empty
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
initialStorage: ConstraintStorage
): Map<TypeConstructor, UnwrappedType> = emptyMap()
override fun writeOnlyStubs(): Boolean = false
}