Extract NewResolvedCallImpl into separate file
This commit is contained in:
-273
@@ -664,279 +664,6 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>() : ResolvedCall<D>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
|
||||||
val resolvedCallAtom: ResolvedCallAtom,
|
|
||||||
substitutor: NewTypeSubstitutor?,
|
|
||||||
private var diagnostics: Collection<KotlinCallDiagnostic>,
|
|
||||||
private val typeApproximator: TypeApproximator,
|
|
||||||
override val languageVersionSettings: LanguageVersionSettings,
|
|
||||||
) : NewAbstractResolvedCall<D>() {
|
|
||||||
var isCompleted = false
|
|
||||||
private set
|
|
||||||
private lateinit var resultingDescriptor: D
|
|
||||||
|
|
||||||
private lateinit var typeArguments: List<UnwrappedType>
|
|
||||||
|
|
||||||
private var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
|
||||||
private var dispatchReceiver = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
|
||||||
private var smartCastDispatchReceiverType: KotlinType? = null
|
|
||||||
private var expectedTypeForSamConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
|
||||||
private var expectedTypeForSuspendConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
|
||||||
private var expectedTypeForUnitConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
|
||||||
private var argumentTypeForConstantConvertedMap: MutableMap<KtExpression, IntegerValueTypeConstant>? = null
|
|
||||||
|
|
||||||
|
|
||||||
override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom
|
|
||||||
|
|
||||||
override fun getStatus(): ResolutionStatus = getResultApplicability(diagnostics).toResolutionStatus()
|
|
||||||
|
|
||||||
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
|
||||||
get() = resolvedCallAtom.argumentMappingByOriginal
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
|
||||||
override fun getResultingDescriptor(): D = resultingDescriptor
|
|
||||||
override fun getExtensionReceiver(): ReceiverValue? = extensionReceiver
|
|
||||||
override fun getDispatchReceiver(): ReceiverValue? = dispatchReceiver
|
|
||||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
|
||||||
|
|
||||||
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
|
|
||||||
val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap()
|
|
||||||
return typeParameters.zip(typeArguments).toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsOnlyOnlyInputTypesErrors() =
|
|
||||||
diagnostics.all { it is KotlinConstraintSystemDiagnostic && it.error is OnlyInputTypesDiagnostic }
|
|
||||||
|
|
||||||
override fun getSmartCastDispatchReceiverType(): KotlinType? = smartCastDispatchReceiverType
|
|
||||||
|
|
||||||
fun updateExtensionReceiverWithSmartCastIfNeeded(smartCastExtensionReceiverType: KotlinType) {
|
|
||||||
if (extensionReceiver is ImplicitClassReceiver) {
|
|
||||||
extensionReceiver = CastImplicitClassReceiver(
|
|
||||||
(extensionReceiver as ImplicitClassReceiver).classDescriptor,
|
|
||||||
smartCastExtensionReceiverType,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
|
||||||
this.smartCastDispatchReceiverType = smartCastDispatchReceiverType
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateDiagnostics(completedDiagnostics: Collection<KotlinCallDiagnostic>) {
|
|
||||||
diagnostics = completedDiagnostics
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateExtensionReceiverType(newType: KotlinType) {
|
|
||||||
if (extensionReceiver?.type == newType) return
|
|
||||||
extensionReceiver = extensionReceiver?.replaceType(newType)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateDispatchReceiverType(newType: KotlinType) {
|
|
||||||
if (dispatchReceiver?.type == newType) return
|
|
||||||
dispatchReceiver = dispatchReceiver?.replaceType(newType)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) {
|
|
||||||
//clear cached values
|
|
||||||
argumentToParameterMap = null
|
|
||||||
_valueArguments = null
|
|
||||||
if (substitutor != null) {
|
|
||||||
// todo: add asset that we do not complete call many times
|
|
||||||
isCompleted = true
|
|
||||||
|
|
||||||
dispatchReceiver?.type?.let {
|
|
||||||
val newType = substitutor.safeSubstitute(it.unwrap())
|
|
||||||
updateDispatchReceiverType(newType)
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionReceiver?.type?.let {
|
|
||||||
val newType = substitutor.safeSubstitute(it.unwrap())
|
|
||||||
updateExtensionReceiverType(newType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
resultingDescriptor = substitutedResultingDescriptor(substitutor) as D
|
|
||||||
|
|
||||||
typeArguments = resolvedCallAtom.freshVariablesSubstitutor.freshVariables.map {
|
|
||||||
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
|
|
||||||
typeApproximator
|
|
||||||
.approximateToSuperType(substituted, TypeApproximatorConfiguration.IntegerLiteralsTypesApproximation)
|
|
||||||
?: substituted
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateExpectedTypeForSamConvertedArgumentMap(substitutor)
|
|
||||||
calculateExpectedTypeForSuspendConvertedArgumentMap(substitutor)
|
|
||||||
calculateExpectedTypeForUnitConvertedArgumentMap(substitutor)
|
|
||||||
calculateExpectedTypeForConstantConvertedArgumentMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinType.withNullabilityFromExplicitTypeArgument(typeArgument: SimpleTypeArgument) =
|
|
||||||
(if (typeArgument.type.isMarkedNullable) makeNullable() else makeNotNullable()).unwrap()
|
|
||||||
|
|
||||||
private fun getSubstitutorWithoutFlexibleTypes(
|
|
||||||
currentSubstitutor: NewTypeSubstitutor?,
|
|
||||||
explicitTypeArguments: List<SimpleTypeArgument>,
|
|
||||||
): NewTypeSubstitutor? {
|
|
||||||
if (currentSubstitutor !is NewTypeSubstitutorByConstructorMap || explicitTypeArguments.isEmpty()) return currentSubstitutor
|
|
||||||
if (!currentSubstitutor.map.any { (_, value) -> value.isFlexible() }) return currentSubstitutor
|
|
||||||
|
|
||||||
val typeVariables = resolvedCallAtom.freshVariablesSubstitutor.freshVariables
|
|
||||||
val newSubstitutorMap = currentSubstitutor.map.toMutableMap()
|
|
||||||
|
|
||||||
explicitTypeArguments.forEachIndexed { index, typeArgument ->
|
|
||||||
val typeVariableConstructor = typeVariables.getOrNull(index)?.freshTypeConstructor ?: return@forEachIndexed
|
|
||||||
|
|
||||||
newSubstitutorMap[typeVariableConstructor] =
|
|
||||||
newSubstitutorMap[typeVariableConstructor]?.withNullabilityFromExplicitTypeArgument(typeArgument)
|
|
||||||
?: return@forEachIndexed
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewTypeSubstitutorByConstructorMap(newSubstitutorMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun substitutedResultingDescriptor(substitutor: NewTypeSubstitutor?) =
|
|
||||||
when (val candidateDescriptor = resolvedCallAtom.candidateDescriptor) {
|
|
||||||
is ClassConstructorDescriptor, is SyntheticMemberDescriptor<*> -> {
|
|
||||||
val explicitTypeArguments = resolvedCallAtom.atom.typeArguments.filterIsInstance<SimpleTypeArgument>()
|
|
||||||
|
|
||||||
candidateDescriptor.substituteInferredVariablesAndApproximate(
|
|
||||||
getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is FunctionDescriptor -> {
|
|
||||||
candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor, candidateDescriptor.isNotSimpleCall())
|
|
||||||
}
|
|
||||||
is PropertyDescriptor -> {
|
|
||||||
if (candidateDescriptor.isNotSimpleCall()) {
|
|
||||||
candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor)
|
|
||||||
} else {
|
|
||||||
candidateDescriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> candidateDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CallableDescriptor.substituteInferredVariablesAndApproximate(
|
|
||||||
substitutor: NewTypeSubstitutor?,
|
|
||||||
shouldApproximate: Boolean = true
|
|
||||||
): CallableDescriptor {
|
|
||||||
val inferredTypeVariablesSubstitutor = substitutor ?: FreshVariableNewTypeSubstitutor.Empty
|
|
||||||
|
|
||||||
// TODO: merge last two substitutors to avoid redundant descriptor substitutions
|
|
||||||
return substitute(resolvedCallAtom.freshVariablesSubstitutor).substitute(resolvedCallAtom.knownParametersSubstitutor)
|
|
||||||
.substituteAndApproximateTypes(inferredTypeVariablesSubstitutor, if (shouldApproximate) typeApproximator else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getArgumentTypeForConstantConvertedArgument(valueArgument: ValueArgument): IntegerValueTypeConstant? {
|
|
||||||
val expression = valueArgument.getArgumentExpression() ?: return null
|
|
||||||
return argumentTypeForConstantConvertedMap?.get(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getExpectedTypeForSamConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
|
||||||
expectedTypeForSamConvertedArgumentMap?.get(valueArgument)
|
|
||||||
|
|
||||||
fun getExpectedTypeForSuspendConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
|
||||||
expectedTypeForSuspendConvertedArgumentMap?.get(valueArgument)
|
|
||||||
|
|
||||||
fun getExpectedTypeForUnitConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
|
||||||
expectedTypeForUnitConvertedArgumentMap?.get(valueArgument)
|
|
||||||
|
|
||||||
private fun calculateExpectedTypeForConstantConvertedArgumentMap() {
|
|
||||||
if (resolvedCallAtom.argumentsWithConstantConversion.isEmpty()) return
|
|
||||||
|
|
||||||
argumentTypeForConstantConvertedMap = hashMapOf()
|
|
||||||
for ((argument, convertedConstant) in resolvedCallAtom.argumentsWithConstantConversion) {
|
|
||||||
val expression = argument.psiExpression ?: continue
|
|
||||||
argumentTypeForConstantConvertedMap!![expression] = convertedConstant
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateExpectedTypeForSamConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
|
||||||
if (resolvedCallAtom.argumentsWithConversion.isEmpty()) return
|
|
||||||
|
|
||||||
expectedTypeForSamConvertedArgumentMap = hashMapOf()
|
|
||||||
for ((argument, description) in resolvedCallAtom.argumentsWithConversion) {
|
|
||||||
val typeWithFreshVariables =
|
|
||||||
resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(description.convertedTypeByCandidateParameter)
|
|
||||||
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
|
||||||
expectedTypeForSamConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateExpectedTypeForSuspendConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
|
||||||
if (resolvedCallAtom.argumentsWithSuspendConversion.isEmpty()) return
|
|
||||||
|
|
||||||
expectedTypeForSuspendConvertedArgumentMap = hashMapOf()
|
|
||||||
for ((argument, convertedType) in resolvedCallAtom.argumentsWithSuspendConversion) {
|
|
||||||
val typeWithFreshVariables = resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(convertedType)
|
|
||||||
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
|
||||||
expectedTypeForSuspendConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateExpectedTypeForUnitConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
|
||||||
if (resolvedCallAtom.argumentsWithUnitConversion.isEmpty()) return
|
|
||||||
|
|
||||||
expectedTypeForUnitConvertedArgumentMap = hashMapOf()
|
|
||||||
for ((argument, convertedType) in resolvedCallAtom.argumentsWithUnitConversion) {
|
|
||||||
val typeWithFreshVariables = resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(convertedType)
|
|
||||||
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
|
||||||
expectedTypeForUnitConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun argumentToParameterMap(
|
|
||||||
resultingDescriptor: CallableDescriptor,
|
|
||||||
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>,
|
|
||||||
): Map<ValueArgument, ArgumentMatchImpl> {
|
|
||||||
val argumentErrors = collectErrorPositions()
|
|
||||||
|
|
||||||
return LinkedHashMap<ValueArgument, ArgumentMatchImpl>().also { result ->
|
|
||||||
for (parameter in resultingDescriptor.valueParameters) {
|
|
||||||
val resolvedArgument = valueArguments[parameter] ?: continue
|
|
||||||
for (argument in resolvedArgument.arguments) {
|
|
||||||
val status = argumentErrors[argument]?.let {
|
|
||||||
ArgumentMatchStatus.TYPE_MISMATCH
|
|
||||||
} ?: ArgumentMatchStatus.SUCCESS
|
|
||||||
result[argument] = ArgumentMatchImpl(parameter).apply { recordMatchStatus(status) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectErrorPositions(): Map<ValueArgument, List<KotlinCallDiagnostic>> {
|
|
||||||
val result = mutableListOf<Pair<ValueArgument, KotlinCallDiagnostic>>()
|
|
||||||
|
|
||||||
fun ConstraintPosition.originalPosition(): ConstraintPosition =
|
|
||||||
if (this is IncorporationConstraintPosition) {
|
|
||||||
from.originalPosition()
|
|
||||||
} else {
|
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.forEach {
|
|
||||||
val position = when (val error = it.constraintSystemError) {
|
|
||||||
is NewConstraintError -> error.position.originalPosition()
|
|
||||||
is CapturedTypeFromSubtyping -> error.position.originalPosition()
|
|
||||||
is ConstrainingTypeIsError -> error.position.originalPosition()
|
|
||||||
else -> null
|
|
||||||
} as? ArgumentConstraintPositionImpl ?: return@forEach
|
|
||||||
|
|
||||||
val argument = position.argument.safeAs<PSIKotlinCallArgument>()?.valueArgument ?: return@forEach
|
|
||||||
result += argument to it
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.groupBy({ it.first }) { it.second }
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
setResultingSubstitutor(substitutor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun CandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
fun CandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
||||||
CandidateApplicability.RESOLVED,
|
CandidateApplicability.RESOLVED,
|
||||||
CandidateApplicability.RESOLVED_LOW_PRIORITY,
|
CandidateApplicability.RESOLVED_LOW_PRIORITY,
|
||||||
|
|||||||
+305
@@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.calls.tower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.substitute
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateTypes
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.isNotSimpleCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.toResolutionStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
|
||||||
|
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||||
|
val resolvedCallAtom: ResolvedCallAtom,
|
||||||
|
substitutor: NewTypeSubstitutor?,
|
||||||
|
private var diagnostics: Collection<KotlinCallDiagnostic>,
|
||||||
|
private val typeApproximator: TypeApproximator,
|
||||||
|
override val languageVersionSettings: LanguageVersionSettings,
|
||||||
|
) : NewAbstractResolvedCall<D>() {
|
||||||
|
var isCompleted = false
|
||||||
|
private set
|
||||||
|
private lateinit var resultingDescriptor: D
|
||||||
|
|
||||||
|
private lateinit var typeArguments: List<UnwrappedType>
|
||||||
|
|
||||||
|
private var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
||||||
|
private var dispatchReceiver = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
||||||
|
private var smartCastDispatchReceiverType: KotlinType? = null
|
||||||
|
private var expectedTypeForSamConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
||||||
|
private var expectedTypeForSuspendConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
||||||
|
private var expectedTypeForUnitConvertedArgumentMap: MutableMap<ValueArgument, UnwrappedType>? = null
|
||||||
|
private var argumentTypeForConstantConvertedMap: MutableMap<KtExpression, IntegerValueTypeConstant>? = null
|
||||||
|
|
||||||
|
|
||||||
|
override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom
|
||||||
|
|
||||||
|
override fun getStatus(): ResolutionStatus = getResultApplicability(diagnostics).toResolutionStatus()
|
||||||
|
|
||||||
|
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||||
|
get() = resolvedCallAtom.argumentMappingByOriginal
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
||||||
|
override fun getResultingDescriptor(): D = resultingDescriptor
|
||||||
|
override fun getExtensionReceiver(): ReceiverValue? = extensionReceiver
|
||||||
|
override fun getDispatchReceiver(): ReceiverValue? = dispatchReceiver
|
||||||
|
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
||||||
|
|
||||||
|
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
|
||||||
|
val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap()
|
||||||
|
return typeParameters.zip(typeArguments).toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun containsOnlyOnlyInputTypesErrors() =
|
||||||
|
diagnostics.all { it is KotlinConstraintSystemDiagnostic && it.error is OnlyInputTypesDiagnostic }
|
||||||
|
|
||||||
|
override fun getSmartCastDispatchReceiverType(): KotlinType? = smartCastDispatchReceiverType
|
||||||
|
|
||||||
|
fun updateExtensionReceiverWithSmartCastIfNeeded(smartCastExtensionReceiverType: KotlinType) {
|
||||||
|
if (extensionReceiver is ImplicitClassReceiver) {
|
||||||
|
extensionReceiver = CastImplicitClassReceiver(
|
||||||
|
(extensionReceiver as ImplicitClassReceiver).classDescriptor,
|
||||||
|
smartCastExtensionReceiverType,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
||||||
|
this.smartCastDispatchReceiverType = smartCastDispatchReceiverType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateDiagnostics(completedDiagnostics: Collection<KotlinCallDiagnostic>) {
|
||||||
|
diagnostics = completedDiagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateExtensionReceiverType(newType: KotlinType) {
|
||||||
|
if (extensionReceiver?.type == newType) return
|
||||||
|
extensionReceiver = extensionReceiver?.replaceType(newType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDispatchReceiverType(newType: KotlinType) {
|
||||||
|
if (dispatchReceiver?.type == newType) return
|
||||||
|
dispatchReceiver = dispatchReceiver?.replaceType(newType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) {
|
||||||
|
//clear cached values
|
||||||
|
argumentToParameterMap = null
|
||||||
|
_valueArguments = null
|
||||||
|
if (substitutor != null) {
|
||||||
|
// todo: add asset that we do not complete call many times
|
||||||
|
isCompleted = true
|
||||||
|
|
||||||
|
dispatchReceiver?.type?.let {
|
||||||
|
val newType = substitutor.safeSubstitute(it.unwrap())
|
||||||
|
updateDispatchReceiverType(newType)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionReceiver?.type?.let {
|
||||||
|
val newType = substitutor.safeSubstitute(it.unwrap())
|
||||||
|
updateExtensionReceiverType(newType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
resultingDescriptor = substitutedResultingDescriptor(substitutor) as D
|
||||||
|
|
||||||
|
typeArguments = resolvedCallAtom.freshVariablesSubstitutor.freshVariables.map {
|
||||||
|
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
|
||||||
|
typeApproximator
|
||||||
|
.approximateToSuperType(substituted, TypeApproximatorConfiguration.IntegerLiteralsTypesApproximation)
|
||||||
|
?: substituted
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateExpectedTypeForSamConvertedArgumentMap(substitutor)
|
||||||
|
calculateExpectedTypeForSuspendConvertedArgumentMap(substitutor)
|
||||||
|
calculateExpectedTypeForUnitConvertedArgumentMap(substitutor)
|
||||||
|
calculateExpectedTypeForConstantConvertedArgumentMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.withNullabilityFromExplicitTypeArgument(typeArgument: SimpleTypeArgument) =
|
||||||
|
(if (typeArgument.type.isMarkedNullable) makeNullable() else makeNotNullable()).unwrap()
|
||||||
|
|
||||||
|
private fun getSubstitutorWithoutFlexibleTypes(
|
||||||
|
currentSubstitutor: NewTypeSubstitutor?,
|
||||||
|
explicitTypeArguments: List<SimpleTypeArgument>,
|
||||||
|
): NewTypeSubstitutor? {
|
||||||
|
if (currentSubstitutor !is NewTypeSubstitutorByConstructorMap || explicitTypeArguments.isEmpty()) return currentSubstitutor
|
||||||
|
if (!currentSubstitutor.map.any { (_, value) -> value.isFlexible() }) return currentSubstitutor
|
||||||
|
|
||||||
|
val typeVariables = resolvedCallAtom.freshVariablesSubstitutor.freshVariables
|
||||||
|
val newSubstitutorMap = currentSubstitutor.map.toMutableMap()
|
||||||
|
|
||||||
|
explicitTypeArguments.forEachIndexed { index, typeArgument ->
|
||||||
|
val typeVariableConstructor = typeVariables.getOrNull(index)?.freshTypeConstructor ?: return@forEachIndexed
|
||||||
|
|
||||||
|
newSubstitutorMap[typeVariableConstructor] =
|
||||||
|
newSubstitutorMap[typeVariableConstructor]?.withNullabilityFromExplicitTypeArgument(typeArgument)
|
||||||
|
?: return@forEachIndexed
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewTypeSubstitutorByConstructorMap(newSubstitutorMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun substitutedResultingDescriptor(substitutor: NewTypeSubstitutor?) =
|
||||||
|
when (val candidateDescriptor = resolvedCallAtom.candidateDescriptor) {
|
||||||
|
is ClassConstructorDescriptor, is SyntheticMemberDescriptor<*> -> {
|
||||||
|
val explicitTypeArguments = resolvedCallAtom.atom.typeArguments.filterIsInstance<SimpleTypeArgument>()
|
||||||
|
|
||||||
|
candidateDescriptor.substituteInferredVariablesAndApproximate(
|
||||||
|
getSubstitutorWithoutFlexibleTypes(substitutor, explicitTypeArguments),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is FunctionDescriptor -> {
|
||||||
|
candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor, candidateDescriptor.isNotSimpleCall())
|
||||||
|
}
|
||||||
|
is PropertyDescriptor -> {
|
||||||
|
if (candidateDescriptor.isNotSimpleCall()) {
|
||||||
|
candidateDescriptor.substituteInferredVariablesAndApproximate(substitutor)
|
||||||
|
} else {
|
||||||
|
candidateDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> candidateDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallableDescriptor.substituteInferredVariablesAndApproximate(
|
||||||
|
substitutor: NewTypeSubstitutor?,
|
||||||
|
shouldApproximate: Boolean = true
|
||||||
|
): CallableDescriptor {
|
||||||
|
val inferredTypeVariablesSubstitutor = substitutor ?: FreshVariableNewTypeSubstitutor.Empty
|
||||||
|
|
||||||
|
// TODO: merge last two substitutors to avoid redundant descriptor substitutions
|
||||||
|
return substitute(resolvedCallAtom.freshVariablesSubstitutor).substitute(resolvedCallAtom.knownParametersSubstitutor)
|
||||||
|
.substituteAndApproximateTypes(inferredTypeVariablesSubstitutor, if (shouldApproximate) typeApproximator else null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getArgumentTypeForConstantConvertedArgument(valueArgument: ValueArgument): IntegerValueTypeConstant? {
|
||||||
|
val expression = valueArgument.getArgumentExpression() ?: return null
|
||||||
|
return argumentTypeForConstantConvertedMap?.get(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getExpectedTypeForSamConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
||||||
|
expectedTypeForSamConvertedArgumentMap?.get(valueArgument)
|
||||||
|
|
||||||
|
fun getExpectedTypeForSuspendConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
||||||
|
expectedTypeForSuspendConvertedArgumentMap?.get(valueArgument)
|
||||||
|
|
||||||
|
fun getExpectedTypeForUnitConvertedArgument(valueArgument: ValueArgument): UnwrappedType? =
|
||||||
|
expectedTypeForUnitConvertedArgumentMap?.get(valueArgument)
|
||||||
|
|
||||||
|
private fun calculateExpectedTypeForConstantConvertedArgumentMap() {
|
||||||
|
if (resolvedCallAtom.argumentsWithConstantConversion.isEmpty()) return
|
||||||
|
|
||||||
|
argumentTypeForConstantConvertedMap = hashMapOf()
|
||||||
|
for ((argument, convertedConstant) in resolvedCallAtom.argumentsWithConstantConversion) {
|
||||||
|
val expression = argument.psiExpression ?: continue
|
||||||
|
argumentTypeForConstantConvertedMap!![expression] = convertedConstant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateExpectedTypeForSamConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
||||||
|
if (resolvedCallAtom.argumentsWithConversion.isEmpty()) return
|
||||||
|
|
||||||
|
expectedTypeForSamConvertedArgumentMap = hashMapOf()
|
||||||
|
for ((argument, description) in resolvedCallAtom.argumentsWithConversion) {
|
||||||
|
val typeWithFreshVariables =
|
||||||
|
resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(description.convertedTypeByCandidateParameter)
|
||||||
|
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
||||||
|
expectedTypeForSamConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateExpectedTypeForSuspendConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
||||||
|
if (resolvedCallAtom.argumentsWithSuspendConversion.isEmpty()) return
|
||||||
|
|
||||||
|
expectedTypeForSuspendConvertedArgumentMap = hashMapOf()
|
||||||
|
for ((argument, convertedType) in resolvedCallAtom.argumentsWithSuspendConversion) {
|
||||||
|
val typeWithFreshVariables = resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(convertedType)
|
||||||
|
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
||||||
|
expectedTypeForSuspendConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateExpectedTypeForUnitConvertedArgumentMap(substitutor: NewTypeSubstitutor?) {
|
||||||
|
if (resolvedCallAtom.argumentsWithUnitConversion.isEmpty()) return
|
||||||
|
|
||||||
|
expectedTypeForUnitConvertedArgumentMap = hashMapOf()
|
||||||
|
for ((argument, convertedType) in resolvedCallAtom.argumentsWithUnitConversion) {
|
||||||
|
val typeWithFreshVariables = resolvedCallAtom.freshVariablesSubstitutor.safeSubstitute(convertedType)
|
||||||
|
val expectedType = substitutor?.safeSubstitute(typeWithFreshVariables) ?: typeWithFreshVariables
|
||||||
|
expectedTypeForUnitConvertedArgumentMap!![argument.psiCallArgument.valueArgument] = expectedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun argumentToParameterMap(
|
||||||
|
resultingDescriptor: CallableDescriptor,
|
||||||
|
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>,
|
||||||
|
): Map<ValueArgument, ArgumentMatchImpl> {
|
||||||
|
val argumentErrors = collectErrorPositions()
|
||||||
|
|
||||||
|
return LinkedHashMap<ValueArgument, ArgumentMatchImpl>().also { result ->
|
||||||
|
for (parameter in resultingDescriptor.valueParameters) {
|
||||||
|
val resolvedArgument = valueArguments[parameter] ?: continue
|
||||||
|
for (argument in resolvedArgument.arguments) {
|
||||||
|
val status = argumentErrors[argument]?.let {
|
||||||
|
ArgumentMatchStatus.TYPE_MISMATCH
|
||||||
|
} ?: ArgumentMatchStatus.SUCCESS
|
||||||
|
result[argument] = ArgumentMatchImpl(parameter).apply { recordMatchStatus(status) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectErrorPositions(): Map<ValueArgument, List<KotlinCallDiagnostic>> {
|
||||||
|
val result = mutableListOf<Pair<ValueArgument, KotlinCallDiagnostic>>()
|
||||||
|
|
||||||
|
fun ConstraintPosition.originalPosition(): ConstraintPosition =
|
||||||
|
if (this is IncorporationConstraintPosition) {
|
||||||
|
from.originalPosition()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.forEach {
|
||||||
|
val position = when (val error = it.constraintSystemError) {
|
||||||
|
is NewConstraintError -> error.position.originalPosition()
|
||||||
|
is CapturedTypeFromSubtyping -> error.position.originalPosition()
|
||||||
|
is ConstrainingTypeIsError -> error.position.originalPosition()
|
||||||
|
else -> null
|
||||||
|
} as? ArgumentConstraintPositionImpl ?: return@forEach
|
||||||
|
|
||||||
|
val argument = position.argument.safeAs<PSIKotlinCallArgument>()?.valueArgument ?: return@forEach
|
||||||
|
result += argument to it
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.groupBy({ it.first }) { it.second }
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
setResultingSubstitutor(substitutor)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user