[FE 1.0] Eliminate resolution ambiguity on inherited SAM-interfaces

^KT-17765 Fixed
This commit is contained in:
Victor Petukhov
2021-11-16 10:59:45 +03:00
committed by teamcityserver
parent a5c6d370dd
commit a6fd14d4e6
27 changed files with 271 additions and 46 deletions
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallArgument
import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.util.CancellationChecker
import java.util.*
@@ -61,6 +60,8 @@ class NewOverloadingConflictResolver(
val resolvedCall = candidate.resolvedCall
val isEliminationAmbiguitiesWithExternalTypeParametersEnabled =
candidate.callComponents.languageVersionSettings.supportsFeature(LanguageFeature.EliminateAmbiguitiesWithExternalTypeParameters)
val isEliminationAmbiguitiesOnInheritedSamInterfacesEnabled =
candidate.callComponents.languageVersionSettings.supportsFeature(LanguageFeature.EliminateAmbiguitiesOnInheritedSamInterfaces)
val descriptor = if (isEliminationAmbiguitiesWithExternalTypeParametersEnabled) {
resolvedCall.candidateDescriptor
} else {
@@ -69,25 +70,30 @@ class NewOverloadingConflictResolver(
val valueParameters = descriptor.valueParameters
var numDefaults = 0
val valueArgumentToParameterType = HashMap<KotlinCallArgument, KotlinType>()
val valueArgumentToParameterType = HashMap<KotlinCallArgument, TypeWithConversion>()
for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) {
if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) {
numDefaults++
} else {
val originalValueParameter = valueParameters[valueParameter.index]
for (valueArgument in resolvedValueArgument.arguments) {
valueArgumentToParameterType[valueArgument] =
candidate.resolvedCall.argumentsWithConversion[valueArgument]?.convertedTypeByOriginParameter
?: valueArgument.getExpectedType(originalValueParameter, candidate.callComponents.languageVersionSettings)
val originalType = candidate.resolvedCall.argumentsWithConversion[valueArgument]?.originalParameterType
val resultType = candidate.resolvedCall.argumentsWithConversion[valueArgument]?.convertedTypeByOriginParameter
?: valueArgument.getExpectedType(originalValueParameter, candidate.callComponents.languageVersionSettings)
valueArgumentToParameterType[valueArgument] = TypeWithConversion(
resultType,
if (isEliminationAmbiguitiesOnInheritedSamInterfacesEnabled) originalType else null
)
}
}
}
return FlatSignature.create(candidate,
descriptor,
numDefaults,
resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] })
return FlatSignature.create(
candidate,
descriptor,
numDefaults,
parameterTypes = resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] })
)
}
@@ -104,7 +104,7 @@ object SamTypeConversions : ParameterTypeConversion {
candidate.resolvedCall.registerArgumentWithSamConversion(
argument,
SamConversionDescription(convertedTypeByOriginal!!, convertedTypeByCandidate)
SamConversionDescription(convertedTypeByOriginal!!, convertedTypeByCandidate, expectedParameterType)
)
if (needCompatibilityResolveForSAM(candidate, expectedParameterType)) {
@@ -89,7 +89,8 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
class SamConversionDescription(
val convertedTypeByOriginParameter: UnwrappedType,
val convertedTypeByCandidateParameter: UnwrappedType // expected type for corresponding argument
val convertedTypeByCandidateParameter: UnwrappedType, // expected type for corresponding argument
val originalParameterType: UnwrappedType // need to overload resolution on inherited SAM interfaces
)
class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() {
@@ -43,6 +43,28 @@ fun <T> FlatSignature.Companion.createFromReflectionType(
)
}
@JvmName("createWithConvertedTypes")
fun <T> FlatSignature.Companion.create(
origin: T,
descriptor: CallableDescriptor,
numDefaults: Int,
parameterTypes: List<TypeWithConversion?>,
): FlatSignature<T> {
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
return FlatSignature(
origin,
descriptor.typeParameters,
valueParameterTypes = extensionReceiverType?.let { listOf(TypeWithConversion(it)) }.orEmpty() + parameterTypes,
hasExtensionReceiver = extensionReceiverType != null,
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
numDefaults = numDefaults,
isExpect = descriptor is MemberDescriptor && descriptor.isExpect,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
)
}
fun <T> FlatSignature.Companion.create(
origin: T,
descriptor: CallableDescriptor,
@@ -54,8 +76,7 @@ fun <T> FlatSignature.Companion.create(
return FlatSignature(
origin,
descriptor.typeParameters,
valueParameterTypes =
listOfNotNull(extensionReceiverType) + parameterTypes,
valueParameterTypes = listOfNotNull(extensionReceiverType) + parameterTypes,
hasExtensionReceiver = extensionReceiverType != null,
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
numDefaults = numDefaults,
@@ -64,10 +85,18 @@ fun <T> FlatSignature.Companion.create(
)
}
fun <D : CallableDescriptor> FlatSignature.Companion.createFromCallableDescriptor(
descriptor: D
): FlatSignature<D> =
create(descriptor, descriptor, numDefaults = 0, parameterTypes = descriptor.valueParameters.map { it.argumentValueType })
fun <D : CallableDescriptor> FlatSignature.Companion.createFromCallableDescriptor(descriptor: D): FlatSignature<D> =
FlatSignature(
descriptor,
descriptor.typeParameters,
valueParameterTypes = listOfNotNull(descriptor.extensionReceiverParameter?.type)
+ descriptor.valueParameters.map { it.argumentValueType },
hasExtensionReceiver = descriptor.extensionReceiverParameter?.type != null,
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
numDefaults = 0,
isExpect = descriptor is MemberDescriptor && descriptor.isExpect,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
)
fun <D : CallableDescriptor> FlatSignature.Companion.createForPossiblyShadowedExtension(descriptor: D): FlatSignature<D> =
FlatSignature(
@@ -26,7 +26,9 @@ import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.descriptorUtil.getKotlinTypeRefiner
import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -176,18 +178,30 @@ open class OverloadingConflictResolver<C : Any>(
}
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
// Attempt 1: general disambiguation
findMaximallySpecificCall(candidates, discriminateGenerics)
// Attempt 2: disambiguation excluding SAM converted candidates
?: hasSAMConversion?.let { hasConversion ->
findMaximallySpecificCall(
candidates.filterNotTo(mutableSetOf()) { hasConversion(it) },
candidates.filterNotTo(mutableSetOf(), hasConversion),
discriminateGenerics
)
}
// Attempt 3: disambiguation excluding synthetic candidates
?: findMaximallySpecificCall(
candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember },
discriminateGenerics
)
// Attempt 4: disambiguation on original SAM-types
?: hasSAMConversion?.let { hasConversion ->
findMaximallySpecificCall(
candidates.filterTo(mutableSetOf(), hasConversion),
discriminateGenerics, useOriginalSamTypes = true
)
}
}
// null means ambiguity between variables
@@ -207,7 +221,7 @@ open class OverloadingConflictResolver<C : Any>(
}
}
private fun findMaximallySpecificCall(candidates: Set<C>, discriminateGenerics: Boolean): C? {
private fun findMaximallySpecificCall(candidates: Set<C>, discriminateGenerics: Boolean, useOriginalSamTypes: Boolean = false): C? {
val filteredCandidates = uniquifyCandidatesSet(candidates)
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
@@ -219,7 +233,7 @@ open class OverloadingConflictResolver<C : Any>(
val bestCandidatesByParameterTypes = conflictingCandidates.filter { candidate ->
cancellationChecker.check()
isMostSpecific(candidate, conflictingCandidates) { call1, call2 ->
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics)
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics, useOriginalSamTypes)
}
}
@@ -262,12 +276,14 @@ open class OverloadingConflictResolver<C : Any>(
private fun isNotLessSpecificCallWithArgumentMapping(
call1: FlatSignature<C>,
call2: FlatSignature<C>,
discriminateGenerics: Boolean
discriminateGenerics: Boolean,
useOriginalSamTypes: Boolean
): Boolean {
return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?: compareCallsByUsedArguments(
call1,
call2,
discriminateGenerics
discriminateGenerics,
useOriginalSamTypes
)
}
@@ -278,7 +294,8 @@ open class OverloadingConflictResolver<C : Any>(
private fun compareCallsByUsedArguments(
call1: FlatSignature<C>,
call2: FlatSignature<C>,
discriminateGenerics: Boolean
discriminateGenerics: Boolean,
useOriginalSamTypes: Boolean
): Boolean {
if (discriminateGenerics) {
val isGeneric1 = call1.isGeneric
@@ -297,7 +314,8 @@ open class OverloadingConflictResolver<C : Any>(
call1,
call2,
SpecificityComparisonWithNumerics,
specificityComparator
specificityComparator,
useOriginalSamTypes
)
}