diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index 2a60c5888eb..c77c915b6f1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -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 + ): 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") } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index e01476d58f6..08c2c1e9b49 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -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>, 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 } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/CallableReferencesCandidateFactory.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/CallableReferencesCandidateFactory.kt index dd5af269740..0c5ba45392f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/CallableReferencesCandidateFactory.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/CallableReferencesCandidateFactory.kt @@ -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 + ): 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 } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 24d1801a827..98c422093b8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -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? abstract var contextReceiversArguments: List abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping abstract val argumentMappingByOriginal: Map diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallAtoms.kt index b88d5b5b7be..159f3c38a05 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallAtoms.kt @@ -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?, open val reflectionCandidateType: UnwrappedType? = null, open val candidate: CallableReferenceResolutionCandidate? = null ) : ResolvedCallAtom() { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/SimpleCandidateFactory.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/SimpleCandidateFactory.kt index 7e94badd93f..d886fdfb64c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/SimpleCandidateFactory.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/SimpleCandidateFactory.kt @@ -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 + ): 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?, initialDiagnostics: Collection, 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 ) } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index 01181444977..0249b3978b4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -154,27 +154,22 @@ private class NoExplicitReceiverScopeTowerProcessor( data.implicitReceiver ) is TowerData.BothTowerLevelAndContextReceiversGroup -> { - val collected = mutableListOf() - val receiversWithCandidates = mutableMapOf>() - 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( 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 -> {} } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index f7b10f93e08..07ec663bb1e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -48,6 +48,12 @@ interface CandidateFactory { ): C fun createErrorCandidate(): C + + fun createCandidate( + towerCandidate: CandidateWithBoundDispatchReceiver, + explicitReceiverKind: ExplicitReceiverKind, + extensionReceiverCandidates: List + ): C } interface CandidateFactoryProviderForInvoke { diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt index 7764f1eed62..be94f429277 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt @@ -20,6 +20,6 @@ fun test() { supertypeMember() member() supertypeExtension() - supertypeExtensionGeneric() + supertypeExtensionGeneric() supertypeContextual() } \ No newline at end of file