[FE] Support multiple candidates for extension receiver
This commit is contained in:
committed by
TeamCityServer
parent
403ec7a5b1
commit
e53cee77a3
+11
-4
@@ -35,10 +35,7 @@ import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceSupport
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
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.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
@@ -492,6 +489,16 @@ class NewResolutionOldInference(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function is called only inside [NoExplicitReceiverScopeTowerProcessor] with [TowerData.BothTowerLevelAndContextReceiversGroup].
|
||||
* This case involves only [SimpleCandidateFactory].
|
||||
*/
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiverCandidates: List<ReceiverValueWithSmartCastInfo>
|
||||
): MyCandidate = error("${this::class.simpleName} doesn't support candidates with multiple extension receiver candidates")
|
||||
|
||||
override fun createErrorCandidate(): MyCandidate {
|
||||
throw IllegalStateException("Not supported creating error candidate for the old type inference candidate factory")
|
||||
}
|
||||
|
||||
+71
-43
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ContextReceiverAmbiguity
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
|
||||
@@ -657,7 +658,70 @@ private fun ResolutionCandidate.prepareExpectedType(expectedType: UnwrappedType)
|
||||
return resolvedCall.knownParametersSubstitutor.safeSubstitute(resultType)
|
||||
}
|
||||
|
||||
private data class ApplicableArgumentWithConstraint(
|
||||
val argument: SimpleKotlinCallArgument,
|
||||
val argumentType: UnwrappedType,
|
||||
val expectedType: UnwrappedType,
|
||||
val position: ConstraintPosition
|
||||
)
|
||||
|
||||
private fun ResolutionCandidate.getArgumentWithConstraintIfCompatible(
|
||||
argument: SimpleKotlinCallArgument,
|
||||
parameter: ParameterDescriptor
|
||||
): ApplicableArgumentWithConstraint? {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
val expectedTypeUnprepared = argument.getExpectedType(parameter, callComponents.languageVersionSettings)
|
||||
val expectedType = prepareExpectedType(expectedTypeUnprepared)
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argument.receiver.stableType, expectedType)
|
||||
val position = ReceiverConstraintPositionImpl(argument)
|
||||
return if (csBuilder.isSubtypeConstraintCompatible(argumentType, expectedType, position))
|
||||
ApplicableArgumentWithConstraint(argument, argumentType, expectedType, position)
|
||||
else null
|
||||
}
|
||||
|
||||
internal object CheckReceivers : ResolutionPart() {
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
when (workIndex) {
|
||||
0 -> checkReceiver(
|
||||
resolvedCall.dispatchReceiverArgument,
|
||||
candidateDescriptor.dispatchReceiverParameter,
|
||||
shouldCheckImplicitInvoke = true,
|
||||
)
|
||||
1 -> {
|
||||
if (resolvedCall.extensionReceiverArgument == null) {
|
||||
resolvedCall.extensionReceiverArgument = chooseExtensionReceiverCandidate() ?: return
|
||||
}
|
||||
checkReceiver(
|
||||
resolvedCall.extensionReceiverArgument,
|
||||
candidateDescriptor.extensionReceiverParameter,
|
||||
shouldCheckImplicitInvoke = false, // reproduce old inference behaviour
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ResolutionCandidate.workCount() = 2
|
||||
|
||||
private fun ResolutionCandidate.chooseExtensionReceiverCandidate(): SimpleKotlinCallArgument? {
|
||||
val receiverCandidates = resolvedCall.extensionReceiverArgumentCandidates
|
||||
if (receiverCandidates.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
if (receiverCandidates.size == 1) {
|
||||
return receiverCandidates.single()
|
||||
}
|
||||
val extensionReceiverParameter = candidateDescriptor.extensionReceiverParameter ?: return null
|
||||
val compatible = receiverCandidates.mapNotNull { getArgumentWithConstraintIfCompatible(it, extensionReceiverParameter) }
|
||||
return when (compatible.size) {
|
||||
0 -> null
|
||||
1 -> compatible.single().argument
|
||||
else -> {
|
||||
addDiagnostic(ContextReceiverAmbiguity())
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolutionCandidate.checkReceiver(
|
||||
receiverArgument: SimpleKotlinCallArgument?,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
@@ -680,25 +744,6 @@ internal object CheckReceivers : ResolutionPart() {
|
||||
|
||||
resolveKotlinArgument(receiverArgument, receiverParameter, receiverInfo)
|
||||
}
|
||||
|
||||
override fun ResolutionCandidate.process(workIndex: Int) {
|
||||
when (workIndex) {
|
||||
0 -> checkReceiver(
|
||||
resolvedCall.dispatchReceiverArgument,
|
||||
candidateDescriptor.dispatchReceiverParameter,
|
||||
shouldCheckImplicitInvoke = true,
|
||||
)
|
||||
1 -> {
|
||||
checkReceiver(
|
||||
resolvedCall.extensionReceiverArgument,
|
||||
candidateDescriptor.extensionReceiverParameter,
|
||||
shouldCheckImplicitInvoke = false, // reproduce old inference behaviour
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ResolutionCandidate.workCount() = 2
|
||||
}
|
||||
|
||||
internal object CheckArgumentsInParenthesis : ResolutionPart() {
|
||||
@@ -822,44 +867,27 @@ internal object CheckContextReceiversResolutionPart : ResolutionPart() {
|
||||
resolvedCall.contextReceiversArguments = contextReceiversArguments
|
||||
}
|
||||
|
||||
private data class ApplicableArgumentWithConstraint(
|
||||
val argument: SimpleKotlinCallArgument,
|
||||
val argumentType: UnwrappedType,
|
||||
val expectedType: UnwrappedType,
|
||||
val position: ConstraintPosition
|
||||
)
|
||||
|
||||
private fun ResolutionCandidate.findContextReceiver(
|
||||
implicitReceiversGroups: List<List<ReceiverValueWithSmartCastInfo>>,
|
||||
candidateContextReceiverParameter: ReceiverParameterDescriptor
|
||||
): SimpleKotlinCallArgument? {
|
||||
|
||||
fun ReceiverValueWithSmartCastInfo.createArgumentIfCompatible(): ApplicableArgumentWithConstraint? {
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
val argument = ReceiverExpressionKotlinCallArgument(this)
|
||||
val expectedTypeUnprepared = argument.getExpectedType(candidateContextReceiverParameter, callComponents.languageVersionSettings)
|
||||
|
||||
val expectedType = prepareExpectedType(expectedTypeUnprepared)
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argument.receiver.stableType, expectedType)
|
||||
val position = ReceiverConstraintPositionImpl(argument)
|
||||
return if (csBuilder.isSubtypeConstraintCompatible(argumentType, expectedType, position))
|
||||
ApplicableArgumentWithConstraint(argument, argumentType, expectedType, position)
|
||||
else null
|
||||
}
|
||||
|
||||
val csBuilder = getSystem().getBuilder()
|
||||
for (implicitReceiverGroup in implicitReceiversGroups) {
|
||||
val applicableArguments = implicitReceiverGroup.mapNotNull { it.createArgumentIfCompatible() }.toList()
|
||||
val applicableArguments = implicitReceiverGroup.mapNotNull {
|
||||
val argument = ReceiverExpressionKotlinCallArgument(it)
|
||||
getArgumentWithConstraintIfCompatible(argument, candidateContextReceiverParameter)
|
||||
}.toList()
|
||||
if (applicableArguments.size == 1) {
|
||||
val (argument, argumentType, expectedType, position) = applicableArguments.single()
|
||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||
return argument
|
||||
}
|
||||
if (applicableArguments.size > 1) {
|
||||
diagnosticsFromResolutionParts.add(MultipleArgumentsApplicableForContextReceiver(candidateContextReceiverParameter))
|
||||
addDiagnostic(MultipleArgumentsApplicableForContextReceiver(candidateContextReceiverParameter))
|
||||
return null
|
||||
}
|
||||
}
|
||||
diagnosticsFromResolutionParts.add(NoContextReceiver(candidateContextReceiverParameter))
|
||||
addDiagnostic(NoContextReceiver(candidateContextReceiverParameter))
|
||||
return null
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -119,6 +119,17 @@ class CallableReferencesCandidateFactory(
|
||||
return createCallableReferenceCallCandidate(diagnostics)
|
||||
}
|
||||
|
||||
/**
|
||||
* The function is called only inside [NoExplicitReceiverScopeTowerProcessor] with [TowerData.BothTowerLevelAndContextReceiversGroup].
|
||||
* This case involves only [SimpleCandidateFactory].
|
||||
*/
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiverCandidates: List<ReceiverValueWithSmartCastInfo>
|
||||
): CallableReferenceResolutionCandidate =
|
||||
error("${this::class.simpleName} doesn't support candidates with multiple extension receiver candidates")
|
||||
|
||||
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
|
||||
createCallableReferenceProcessor(scopeTower, kotlinCall.rhsName, this, explicitReceiver)
|
||||
|
||||
@@ -377,7 +388,7 @@ class CallableReferencesCandidateFactory(
|
||||
(suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION && buildTypeWithConversions)
|
||||
|
||||
callComponents.reflectionTypes.getKFunctionType(
|
||||
Annotations.EMPTY, null, argumentsAndReceivers, null,
|
||||
Annotations.EMPTY, null, emptyList(), argumentsAndReceivers, null,
|
||||
returnType, descriptor.builtIns, isSuspend
|
||||
) to callableReferenceAdaptation
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
|
||||
abstract val candidateDescriptor: CallableDescriptor
|
||||
abstract val explicitReceiverKind: ExplicitReceiverKind
|
||||
abstract val dispatchReceiverArgument: SimpleKotlinCallArgument?
|
||||
abstract val extensionReceiverArgument: SimpleKotlinCallArgument?
|
||||
abstract var extensionReceiverArgument: SimpleKotlinCallArgument?
|
||||
abstract val extensionReceiverArgumentCandidates: List<SimpleKotlinCallArgument>?
|
||||
abstract var contextReceiversArguments: List<SimpleKotlinCallArgument>
|
||||
abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
|
||||
+3
-2
@@ -73,7 +73,7 @@ class ResolvedCallableReferenceCallAtom(
|
||||
reflectionCandidateType: UnwrappedType? = null,
|
||||
candidate: CallableReferenceResolutionCandidate? = null
|
||||
) : MutableResolvedCallAtom(
|
||||
atom, candidateDescriptor, explicitReceiverKind, dispatchReceiverArgument, extensionReceiverArgument, reflectionCandidateType, candidate
|
||||
atom, candidateDescriptor, explicitReceiverKind, dispatchReceiverArgument, extensionReceiverArgument, emptyList(), reflectionCandidateType, candidate
|
||||
), ResolvedCallableReferenceAtom
|
||||
|
||||
open class MutableResolvedCallAtom(
|
||||
@@ -81,7 +81,8 @@ open class MutableResolvedCallAtom(
|
||||
originalCandidateDescriptor: CallableDescriptor, // original candidate descriptor
|
||||
override val explicitReceiverKind: ExplicitReceiverKind,
|
||||
override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||
override val extensionReceiverArgument: SimpleKotlinCallArgument?,
|
||||
override var extensionReceiverArgument: SimpleKotlinCallArgument?,
|
||||
override val extensionReceiverArgumentCandidates: List<SimpleKotlinCallArgument>?,
|
||||
open val reflectionCandidateType: UnwrappedType? = null,
|
||||
open val candidate: CallableReferenceResolutionCandidate? = null
|
||||
) : ResolvedCallAtom() {
|
||||
|
||||
+26
-5
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.model
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.components.NewConstraintSystemImpl
|
||||
@@ -77,7 +78,7 @@ class SimpleCandidateFactory(
|
||||
ReceiverExpressionKotlinCallArgument(it, isSafeCall)
|
||||
}
|
||||
return createCandidate(
|
||||
givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null,
|
||||
givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null, null,
|
||||
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor
|
||||
)
|
||||
}
|
||||
@@ -96,7 +97,26 @@ class SimpleCandidateFactory(
|
||||
|
||||
return createCandidate(
|
||||
towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver,
|
||||
extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null
|
||||
extensionArgumentReceiver, null, towerCandidate.diagnostics, knownSubstitutor = null
|
||||
)
|
||||
}
|
||||
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiverCandidates: List<ReceiverValueWithSmartCastInfo>
|
||||
): SimpleResolutionCandidate {
|
||||
val dispatchArgumentReceiver = createReceiverArgument(
|
||||
kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind),
|
||||
towerCandidate.dispatchReceiver
|
||||
)
|
||||
val extensionArgumentReceiverCandidates = extensionReceiverCandidates.mapNotNull {
|
||||
createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), it)
|
||||
}
|
||||
|
||||
return createCandidate(
|
||||
towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver,
|
||||
null, extensionArgumentReceiverCandidates, towerCandidate.diagnostics, knownSubstitutor = null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -105,12 +125,13 @@ class SimpleCandidateFactory(
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
dispatchArgumentReceiver: SimpleKotlinCallArgument?,
|
||||
extensionArgumentReceiver: SimpleKotlinCallArgument?,
|
||||
extensionArgumentReceiverCandidates: List<SimpleKotlinCallArgument>?,
|
||||
initialDiagnostics: Collection<KotlinCallDiagnostic>,
|
||||
knownSubstitutor: TypeSubstitutor?
|
||||
): SimpleResolutionCandidate {
|
||||
val resolvedKtCall = MutableResolvedCallAtom(
|
||||
kotlinCall, descriptor, explicitReceiverKind,
|
||||
dispatchArgumentReceiver, extensionArgumentReceiver
|
||||
dispatchArgumentReceiver, extensionArgumentReceiver, extensionArgumentReceiverCandidates
|
||||
)
|
||||
|
||||
if (ErrorUtils.isError(descriptor)) {
|
||||
@@ -126,7 +147,7 @@ class SimpleCandidateFactory(
|
||||
candidate.addDiagnostic(HiddenDescriptor)
|
||||
}
|
||||
|
||||
if (extensionArgumentReceiver != null) {
|
||||
if (extensionArgumentReceiver != null && descriptor !is ClassConstructorDescriptor) {
|
||||
val parameterIsDynamic = descriptor.extensionReceiverParameter!!.value.type.isDynamic()
|
||||
val argumentIsDynamic = extensionArgumentReceiver.receiver.receiverValue.type.isDynamic()
|
||||
|
||||
@@ -153,7 +174,7 @@ class SimpleCandidateFactory(
|
||||
|
||||
return createCandidate(
|
||||
errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null,
|
||||
initialDiagnostics = listOf(), knownSubstitutor = null
|
||||
extensionArgumentReceiverCandidates = null, initialDiagnostics = listOf(), knownSubstitutor = null
|
||||
)
|
||||
}
|
||||
}
|
||||
+15
-19
@@ -154,27 +154,22 @@ private class NoExplicitReceiverScopeTowerProcessor<C : Candidate>(
|
||||
data.implicitReceiver
|
||||
)
|
||||
is TowerData.BothTowerLevelAndContextReceiversGroup -> {
|
||||
val collected = mutableListOf<CandidateWithBoundDispatchReceiver>()
|
||||
val receiversWithCandidates = mutableMapOf<ReceiverValueWithSmartCastInfo, List<CandidateWithBoundDispatchReceiver>>()
|
||||
for (contextReceiver in data.contextReceiversGroup) {
|
||||
val collectedFromReceiver = data.level.collectCandidates(contextReceiver).toMutableList()
|
||||
collectedFromReceiver.removeIf { collectedCandidate ->
|
||||
val duplicate = collected.find { it.descriptor == collectedCandidate.descriptor }
|
||||
if (duplicate != null) {
|
||||
duplicate.diagnostics.add(ContextReceiverAmbiguity())
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
collected.addAll(collectedFromReceiver)
|
||||
receiversWithCandidates[contextReceiver] = collectedFromReceiver
|
||||
val groupsOfDuplicateCandidates = data.contextReceiversGroup.flatMap { receiver ->
|
||||
data.level.collectCandidates(receiver).map { it to receiver }
|
||||
}.filter { (candidate, _) ->
|
||||
candidate.requiresExtensionReceiver
|
||||
}.groupBy { it.first.descriptor }.values
|
||||
|
||||
val candidateToReceivers = groupsOfDuplicateCandidates.map { l ->
|
||||
val candidate = l.first().first
|
||||
val receivers = l.map { it.second }
|
||||
candidate to receivers
|
||||
}
|
||||
receiversWithCandidates.flatMap {
|
||||
createCandidates(
|
||||
it.value,
|
||||
candidateToReceivers.map {
|
||||
candidateFactory.createCandidate(
|
||||
it.first,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
it.key
|
||||
it.second
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -186,6 +181,7 @@ private class NoExplicitReceiverScopeTowerProcessor<C : Candidate>(
|
||||
when (data) {
|
||||
is TowerData.TowerLevel -> data.level.recordLookup(name)
|
||||
is TowerData.BothTowerLevelAndImplicitReceiver -> data.level.recordLookup(name)
|
||||
is TowerData.BothTowerLevelAndContextReceiversGroup -> data.level.recordLookup(name)
|
||||
is TowerData.ForLookupForNoExplicitReceiver -> data.level.recordLookup(name)
|
||||
else -> {}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,12 @@ interface CandidateFactory<out C : Candidate> {
|
||||
): C
|
||||
|
||||
fun createErrorCandidate(): C
|
||||
|
||||
fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiverCandidates: List<ReceiverValueWithSmartCastInfo>
|
||||
): C
|
||||
}
|
||||
|
||||
interface CandidateFactoryProviderForInvoke<C : Candidate> {
|
||||
|
||||
+1
-1
@@ -20,6 +20,6 @@ fun test() {
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>supertypeMember<!>()
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>member<!>()
|
||||
<!AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER!>supertypeExtension()<!>
|
||||
<!AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER!>supertypeExtensionGeneric()<!>
|
||||
<!AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>supertypeExtensionGeneric<!>()<!>
|
||||
<!MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER!>supertypeContextual()<!>
|
||||
}
|
||||
Reference in New Issue
Block a user