[FE 1.0] Eliminate resolution ambiguity on inherited SAM-interfaces
^KT-17765 Fixed
This commit is contained in:
committed by
teamcityserver
parent
a5c6d370dd
commit
a6fd14d4e6
+16
-10
@@ -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] })
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+35
-6
@@ -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(
|
||||
|
||||
+25
-7
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user