FIR: Add preliminary support for context receivers in resolution
This commit is contained in:
@@ -119,7 +119,7 @@ class FirCallResolver(
|
||||
functionCall.copyAsImplicitInvokeCall {
|
||||
explicitReceiver = candidate.callInfo.explicitReceiver
|
||||
dispatchReceiver = candidate.dispatchReceiverExpression()
|
||||
extensionReceiver = candidate.extensionReceiverExpression()
|
||||
extensionReceiver = candidate.chosenExtensionReceiverExpression()
|
||||
argumentList = candidate.callInfo.argumentList
|
||||
}
|
||||
} else {
|
||||
@@ -381,7 +381,7 @@ class FirCallResolver(
|
||||
if (reducedCandidates.size == 1) {
|
||||
val candidate = reducedCandidates.single()
|
||||
resultExpression = resultExpression.transformDispatchReceiver(StoreReceiver, candidate.dispatchReceiverExpression())
|
||||
resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.extensionReceiverExpression())
|
||||
resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.chosenExtensionReceiverExpression())
|
||||
}
|
||||
if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression)
|
||||
return resultExpression
|
||||
|
||||
@@ -47,9 +47,10 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
@@ -73,7 +74,10 @@ fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupT
|
||||
}
|
||||
val rawReturnType = (this as FirCallableDeclaration).returnTypeRef.coneType
|
||||
|
||||
return createFunctionalType(parameters, receiverTypeRef?.coneType, rawReturnType, isSuspend = isSuspend)
|
||||
return createFunctionalType(
|
||||
parameters, receiverTypeRef?.coneType, rawReturnType, isSuspend = isSuspend,
|
||||
contextReceivers = contextReceivers.map { it.typeRef.coneType }
|
||||
)
|
||||
}
|
||||
|
||||
fun FirFunction.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef {
|
||||
@@ -88,9 +92,16 @@ fun createFunctionalType(
|
||||
receiverType: ConeKotlinType?,
|
||||
rawReturnType: ConeKotlinType,
|
||||
isSuspend: Boolean,
|
||||
contextReceivers: List<ConeKotlinType> = emptyList(),
|
||||
isKFunctionType: Boolean = false
|
||||
): ConeLookupTagBasedType {
|
||||
val receiverAndParameterTypes = listOfNotNull(receiverType) + parameters + listOf(rawReturnType)
|
||||
val receiverAndParameterTypes =
|
||||
buildList {
|
||||
addAll(contextReceivers)
|
||||
addIfNotNull(receiverType)
|
||||
addAll(parameters)
|
||||
add(rawReturnType)
|
||||
}
|
||||
|
||||
val kind = if (isSuspend) {
|
||||
if (isKFunctionType) FunctionClassKind.KSuspendFunction else FunctionClassKind.SuspendFunction
|
||||
@@ -99,7 +110,18 @@ fun createFunctionalType(
|
||||
}
|
||||
|
||||
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(receiverAndParameterTypes.size - 1))
|
||||
val attributes = if (receiverType != null) ConeAttributes.WithExtensionFunctionType else ConeAttributes.Empty
|
||||
val attributes = when {
|
||||
contextReceivers.isNotEmpty() -> ConeAttributes.create(
|
||||
buildList {
|
||||
add(CompilerConeAttributes.ContextFunctionTypeParams(contextReceivers.size))
|
||||
if (receiverType != null) {
|
||||
add(CompilerConeAttributes.ExtensionFunctionType)
|
||||
}
|
||||
}
|
||||
)
|
||||
receiverType != null -> ConeAttributes.WithExtensionFunctionType
|
||||
else -> ConeAttributes.Empty
|
||||
}
|
||||
return ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(functionalTypeId),
|
||||
receiverAndParameterTypes.toTypedArray(),
|
||||
|
||||
@@ -16,6 +16,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
CollectTypeVariableUsagesInfo,
|
||||
CheckDispatchReceiver,
|
||||
CheckExtensionReceiver,
|
||||
CheckContextReceivers,
|
||||
CheckDslScopeViolation,
|
||||
CheckLowPriorityInOverloadResolution,
|
||||
PostponedVariablesInitializerResolutionStage,
|
||||
@@ -43,6 +44,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
CollectTypeVariableUsagesInfo,
|
||||
CheckDispatchReceiver,
|
||||
CheckExtensionReceiver,
|
||||
CheckContextReceivers,
|
||||
CheckDslScopeViolation,
|
||||
CheckArguments,
|
||||
CheckCallModifiers,
|
||||
@@ -113,6 +115,7 @@ class ResolutionSequenceBuilder(
|
||||
var mapTypeArguments: Boolean = false,
|
||||
var resolveCallableReferenceArguments: Boolean = false,
|
||||
var checkCallableReferenceExpectedType: Boolean = false,
|
||||
val checkContextReceivers: Boolean = false,
|
||||
) {
|
||||
fun build(): CallKind {
|
||||
val stages = mutableListOf<ResolutionStage>().apply {
|
||||
@@ -125,6 +128,7 @@ class ResolutionSequenceBuilder(
|
||||
if (checkDispatchReceiver) add(CheckDispatchReceiver)
|
||||
if (checkExtensionReceiver) add(CheckExtensionReceiver)
|
||||
if (checkArguments) add(CheckArguments)
|
||||
if (checkContextReceivers) add(CheckContextReceivers)
|
||||
if (resolveCallableReferenceArguments) add(EagerResolveOfCallableReferences)
|
||||
if (checkLowPriorityInOverloadResolution) add(CheckLowPriorityInOverloadResolution)
|
||||
if (initializePostponedVariables) add(PostponedVariablesInitializerResolutionStage)
|
||||
|
||||
@@ -28,9 +28,11 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
class Candidate(
|
||||
override val symbol: FirBasedSymbol<*>,
|
||||
override val dispatchReceiverValue: ReceiverValue?,
|
||||
override val extensionReceiverValue: ReceiverValue?,
|
||||
// In most cases, it contains zero or single element
|
||||
// More than one, only in case of context receiver group
|
||||
val givenExtensionReceiverOptions: List<ReceiverValue>,
|
||||
override val explicitReceiverKind: ExplicitReceiverKind,
|
||||
val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory,
|
||||
private val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory,
|
||||
private val baseSystem: ConstraintStorage,
|
||||
override val callInfo: CallInfo,
|
||||
val originScope: FirScope?,
|
||||
@@ -73,6 +75,10 @@ class Candidate(
|
||||
var currentApplicability = CandidateApplicability.RESOLVED
|
||||
private set
|
||||
|
||||
override var chosenExtensionReceiverValue: ReceiverValue? = givenExtensionReceiverOptions.singleOrNull()
|
||||
|
||||
var contextReceiverArguments: List<FirExpression>? = null
|
||||
|
||||
override val applicability: CandidateApplicability
|
||||
get() = currentApplicability
|
||||
|
||||
@@ -95,8 +101,8 @@ class Candidate(
|
||||
fun dispatchReceiverExpression(): FirExpression =
|
||||
dispatchReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||
|
||||
fun extensionReceiverExpression(): FirExpression =
|
||||
extensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||
fun chosenExtensionReceiverExpression(): FirExpression =
|
||||
chosenExtensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||
|
||||
var hasVisibleBackingField = false
|
||||
|
||||
|
||||
@@ -49,19 +49,20 @@ class CandidateFactory private constructor(
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
scope: FirScope?,
|
||||
dispatchReceiverValue: ReceiverValue? = null,
|
||||
extensionReceiverValue: ReceiverValue? = null,
|
||||
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
|
||||
objectsByName: Boolean = false
|
||||
): Candidate {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val symbol = symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo)
|
||||
|
||||
val result = Candidate(
|
||||
symbol, dispatchReceiverValue, extensionReceiverValue,
|
||||
symbol, dispatchReceiverValue, givenExtensionReceiverOptions,
|
||||
explicitReceiverKind, context.inferenceComponents.constraintSystemFactory, baseSystem,
|
||||
callInfo,
|
||||
scope,
|
||||
isFromCompanionObjectTypeScope = when (explicitReceiverKind) {
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> extensionReceiverValue.isCandidateFromCompanionObjectTypeScope()
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER ->
|
||||
givenExtensionReceiverOptions.singleOrNull().isCandidateFromCompanionObjectTypeScope()
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiverValue.isCandidateFromCompanionObjectTypeScope()
|
||||
// The following cases are not applicable for companion objects.
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> false
|
||||
@@ -121,7 +122,7 @@ class CandidateFactory private constructor(
|
||||
return Candidate(
|
||||
symbol,
|
||||
dispatchReceiverValue = null,
|
||||
extensionReceiverValue = null,
|
||||
givenExtensionReceiverOptions = emptyList(),
|
||||
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
context.inferenceComponents.constraintSystemFactory,
|
||||
baseSystem,
|
||||
|
||||
+108
-10
@@ -34,6 +34,8 @@ import org.jetbrains.kotlin.fir.visibilityChecker
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.isSubtypeConstraintCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
|
||||
@@ -76,18 +78,43 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
object CheckExtensionReceiver : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
||||
val expectedReceiverType = candidate.getReceiverType(context) ?: return
|
||||
|
||||
val argumentExtensionReceiverValue = candidate.extensionReceiverValue ?: return
|
||||
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
|
||||
argumentType = argumentExtensionReceiverValue.type,
|
||||
expectedType = expectedType,
|
||||
session = context.session
|
||||
)
|
||||
|
||||
// Probably, we should add an assertion here since we check consistency on the level of scope tower levels
|
||||
if (candidate.givenExtensionReceiverOptions.isEmpty()) return
|
||||
|
||||
val preparedReceivers = candidate.givenExtensionReceiverOptions.map {
|
||||
candidate.prepareReceivers(it, expectedType, context)
|
||||
}
|
||||
|
||||
if (preparedReceivers.size == 1) {
|
||||
resolveExtensionReceiver(preparedReceivers, candidate, expectedType, sink, context)
|
||||
return
|
||||
}
|
||||
|
||||
val successfulReceivers = preparedReceivers.filter {
|
||||
candidate.system.isSubtypeConstraintCompatible(it.type, expectedType, SimpleConstraintSystemConstraintPosition)
|
||||
}
|
||||
|
||||
when (successfulReceivers.size) {
|
||||
0 -> sink.yieldDiagnostic(InapplicableWrongReceiver())
|
||||
1 -> resolveExtensionReceiver(successfulReceivers, candidate, expectedType, sink, context)
|
||||
else -> sink.yieldDiagnostic(MultipleContextReceiversApplicableForExtensionReceivers())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveExtensionReceiver(
|
||||
receivers: List<ReceiverDescription>,
|
||||
candidate: Candidate,
|
||||
expectedType: ConeKotlinType,
|
||||
sink: CheckerSink,
|
||||
context: ResolutionContext
|
||||
) {
|
||||
val receiver = receivers.single()
|
||||
candidate.resolvePlainArgumentType(
|
||||
candidate.csBuilder,
|
||||
argumentExtensionReceiverValue.receiverExpression,
|
||||
argumentType = argumentType,
|
||||
receiver.expression,
|
||||
argumentType = receiver.type,
|
||||
expectedType = expectedType,
|
||||
sink = sink,
|
||||
context = context,
|
||||
@@ -109,6 +136,25 @@ object CheckExtensionReceiver : ResolutionStage() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Candidate.prepareReceivers(
|
||||
argumentExtensionReceiverValue: ReceiverValue,
|
||||
expectedType: ConeKotlinType,
|
||||
context: ResolutionContext,
|
||||
): ReceiverDescription {
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
|
||||
argumentType = argumentExtensionReceiverValue.type,
|
||||
expectedType = expectedType,
|
||||
session = context.session
|
||||
).let { prepareCapturedType(it, context) }
|
||||
|
||||
return ReceiverDescription(argumentExtensionReceiverValue.receiverExpression, argumentType)
|
||||
}
|
||||
|
||||
private class ReceiverDescription(
|
||||
val expression: FirExpression,
|
||||
val type: ConeKotlinType,
|
||||
)
|
||||
|
||||
object CheckDispatchReceiver : ResolutionStage() {
|
||||
@OptIn(SymbolInternals::class)
|
||||
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
||||
@@ -156,6 +202,58 @@ object CheckDispatchReceiver : ResolutionStage() {
|
||||
}
|
||||
}
|
||||
|
||||
object CheckContextReceivers : ResolutionStage() {
|
||||
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
||||
val contextReceiverExpectedTypes = (candidate.symbol as? FirCallableSymbol<*>)?.fir?.contextReceivers?.map {
|
||||
candidate.substitutor.substituteOrSelf(it.typeRef.coneType)
|
||||
}?.takeUnless { it.isEmpty() } ?: return
|
||||
|
||||
val receiverGroups: List<List<ImplicitReceiverValue<*>>> =
|
||||
context.bodyResolveContext.towerDataContext.towerDataElements.mapNotNull { towerDataElement ->
|
||||
towerDataElement.implicitReceiver?.let(::listOf) ?: towerDataElement.contextReceiverGroup
|
||||
}
|
||||
|
||||
val resultingContextReceiverArguments = mutableListOf<FirExpression>()
|
||||
for (expectedType in contextReceiverExpectedTypes) {
|
||||
val matchingReceivers = candidate.findClosestMatchingReceivers(expectedType, receiverGroups, context)
|
||||
when (matchingReceivers.size) {
|
||||
0 -> {
|
||||
sink.reportDiagnostic(NoApplicableValueForContextReceiver(expectedType))
|
||||
return
|
||||
}
|
||||
1 -> {
|
||||
val matchingReceiver = matchingReceivers.single()
|
||||
resultingContextReceiverArguments.add(matchingReceiver.expression)
|
||||
candidate.system.addSubtypeConstraint(matchingReceiver.type, expectedType, SimpleConstraintSystemConstraintPosition)
|
||||
}
|
||||
else -> {
|
||||
sink.reportDiagnostic(AmbiguousValuesForContextReceiverParameter(expectedType))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
candidate.contextReceiverArguments = resultingContextReceiverArguments
|
||||
}
|
||||
}
|
||||
|
||||
private fun Candidate.findClosestMatchingReceivers(
|
||||
expectedType: ConeKotlinType,
|
||||
receiverGroups: List<List<ImplicitReceiverValue<*>>>,
|
||||
context: ResolutionContext,
|
||||
): List<ReceiverDescription> {
|
||||
for (receiverGroup in receiverGroups) {
|
||||
val currentResult =
|
||||
receiverGroup
|
||||
.map { prepareReceivers(it, expectedType, context) }
|
||||
.filter { system.isSubtypeConstraintCompatible(it.type, expectedType, SimpleConstraintSystemConstraintPosition) }
|
||||
|
||||
if (currentResult.isNotEmpty()) return currentResult
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-dsl-marker/ for more details and
|
||||
* /compiler/testData/diagnostics/tests/resolve/dslMarker for the test files.
|
||||
@@ -176,7 +274,7 @@ object CheckDslScopeViolation : ResolutionStage() {
|
||||
}
|
||||
}
|
||||
checkReceiverValue(candidate.dispatchReceiverValue)
|
||||
checkReceiverValue(candidate.extensionReceiverValue)
|
||||
checkReceiverValue(candidate.chosenExtensionReceiverValue)
|
||||
|
||||
// For value of builtin functional type with implicit extension receiver, the receiver is passed as the first argument rather than
|
||||
// an extension receiver of the `invoke` call. Hence, we need to specially handle this case.
|
||||
|
||||
+8
-1
@@ -162,7 +162,7 @@ internal class FirInvokeResolveTowerExtension(
|
||||
continue
|
||||
}
|
||||
|
||||
val extensionReceiverExpression = invokeReceiverCandidate.extensionReceiverExpression()
|
||||
val extensionReceiverExpression = invokeReceiverCandidate.chosenExtensionReceiverExpression()
|
||||
val useImplicitReceiverAsBuiltinInvokeArgument =
|
||||
!invokeBuiltinExtensionMode && isExtensionFunctionType &&
|
||||
invokeReceiverCandidate.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
@@ -391,6 +391,13 @@ private class InvokeFunctionResolveTask(
|
||||
info, group.Member,
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
},
|
||||
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
|
||||
processLevelForRegularInvoke(
|
||||
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
|
||||
info, towerGroup.Member,
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
+84
-19
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
@@ -47,6 +48,12 @@ internal class TowerDataElementsForName(
|
||||
}
|
||||
}
|
||||
|
||||
val contextReceiverGroups by lazy(LazyThreadSafetyMode.NONE) {
|
||||
nonLocalTowerDataElements.mapIndexedNotNull { index, towerDataElement ->
|
||||
towerDataElement.contextReceiverGroup?.let { receiver -> IndexedValue(index, receiver) }
|
||||
}
|
||||
}
|
||||
|
||||
val emptyScopes = mutableSetOf<FirScope>()
|
||||
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
|
||||
}
|
||||
@@ -81,22 +88,34 @@ internal abstract class FirBaseTowerResolveTask(
|
||||
extensionReceiver: ReceiverValue? = null,
|
||||
withHideMembersOnly: Boolean = false,
|
||||
includeInnerConstructors: Boolean = extensionReceiver != null,
|
||||
contextReceiverGroup: ContextReceiverGroup? = null,
|
||||
): ScopeTowerLevel = ScopeTowerLevel(
|
||||
components, this,
|
||||
extensionReceiver, withHideMembersOnly, includeInnerConstructors
|
||||
givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
||||
withHideMembersOnly, includeInnerConstructors
|
||||
)
|
||||
|
||||
protected fun ReceiverValue.toMemberScopeTowerLevel(
|
||||
extensionReceiver: ReceiverValue? = null
|
||||
extensionReceiver: ReceiverValue? = null,
|
||||
contextReceiverGroup: ContextReceiverGroup? = null,
|
||||
) = MemberScopeTowerLevel(
|
||||
components, this,
|
||||
extensionReceiver,
|
||||
givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
||||
)
|
||||
|
||||
protected fun ContextReceiverGroup.toMemberScopeTowerLevel(
|
||||
extensionReceiver: ReceiverValue? = null,
|
||||
otherContextReceiverGroup: ContextReceiverGroup? = null,
|
||||
) = ContextReceiverGroupMemberScopeTowerLevel(
|
||||
components, this,
|
||||
givenExtensionReceiverOptions = otherContextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
||||
)
|
||||
|
||||
protected inline fun enumerateTowerLevels(
|
||||
parentGroup: TowerGroup = TowerGroup.EmptyRoot,
|
||||
onScope: (FirScope, TowerGroup) -> Unit,
|
||||
onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit,
|
||||
onContextReceiverGroup: (ContextReceiverGroup, TowerGroup) -> Unit,
|
||||
) {
|
||||
for ((index, localScope) in towerDataElementsForName.reversedFilteredLocalScopes) {
|
||||
onScope(localScope, parentGroup.Local(index))
|
||||
@@ -118,6 +137,10 @@ internal abstract class FirBaseTowerResolveTask(
|
||||
onImplicitReceiver(receiver, parentGroup.Implicit(depth))
|
||||
}
|
||||
}
|
||||
|
||||
for ((depth, contextReceiverGroup) in towerDataElementsForName.contextReceiverGroups) {
|
||||
onContextReceiverGroup(contextReceiverGroup, parentGroup.ContextReceiverGroup(depth))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +266,17 @@ internal open class FirTowerResolveTask(
|
||||
)
|
||||
},
|
||||
onImplicitReceiver = { implicitReceiverValue, group ->
|
||||
processCombinationOfReceivers(implicitReceiverValue, explicitReceiverValue, info, group)
|
||||
// Member extensions
|
||||
processLevel(
|
||||
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
|
||||
info, group.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
},
|
||||
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
|
||||
processLevel(
|
||||
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
|
||||
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -277,7 +310,13 @@ internal open class FirTowerResolveTask(
|
||||
implicitReceiverValuesWithEmptyScopes,
|
||||
emptyScopes
|
||||
)
|
||||
}
|
||||
},
|
||||
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
|
||||
processCandidatesWithGivenContextReceiverGroup(
|
||||
contextReceiverGroup,
|
||||
info, towerGroup,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -308,6 +347,7 @@ internal open class FirTowerResolveTask(
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup
|
||||
)
|
||||
} else {
|
||||
// context?
|
||||
for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) {
|
||||
processHideMembersLevel(
|
||||
implicitReceiverValue, topLevelScope, info, index, depth,
|
||||
@@ -331,19 +371,6 @@ internal open class FirTowerResolveTask(
|
||||
|
||||
}
|
||||
|
||||
private suspend fun processCombinationOfReceivers(
|
||||
implicitReceiverValue: ImplicitReceiverValue<*>,
|
||||
explicitReceiverValue: ExpressionReceiverValue,
|
||||
info: CallInfo,
|
||||
parentGroup: TowerGroup
|
||||
) {
|
||||
// Member extensions
|
||||
processLevel(
|
||||
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
|
||||
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
|
||||
receiver: ImplicitReceiverValue<*>,
|
||||
info: CallInfo,
|
||||
@@ -377,11 +404,49 @@ internal open class FirTowerResolveTask(
|
||||
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
|
||||
info, group
|
||||
)
|
||||
}
|
||||
},
|
||||
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
|
||||
processLevel(
|
||||
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = receiver),
|
||||
info, towerGroup
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private suspend fun processCandidatesWithGivenContextReceiverGroup(
|
||||
contextReceiverGroup: ContextReceiverGroup,
|
||||
info: CallInfo,
|
||||
parentGroup: TowerGroup,
|
||||
) {
|
||||
processLevel(
|
||||
contextReceiverGroup.toMemberScopeTowerLevel(), info, parentGroup.Member,
|
||||
)
|
||||
|
||||
enumerateTowerLevels(
|
||||
parentGroup,
|
||||
onScope = { scope, towerGroup ->
|
||||
processLevel(
|
||||
scope.toScopeTowerLevel(contextReceiverGroup = contextReceiverGroup),
|
||||
info, towerGroup,
|
||||
)
|
||||
},
|
||||
onImplicitReceiver = { implicitReceiverValue, towerGroup ->
|
||||
processLevel(
|
||||
implicitReceiverValue.toMemberScopeTowerLevel(contextReceiverGroup = contextReceiverGroup),
|
||||
info, towerGroup
|
||||
)
|
||||
},
|
||||
onContextReceiverGroup = { otherContextReceiverGroup, towerGroup ->
|
||||
processLevel(
|
||||
contextReceiverGroup.toMemberScopeTowerLevel(otherContextReceiverGroup = otherContextReceiverGroup),
|
||||
info, towerGroup,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun processHideMembersLevel(
|
||||
receiverValue: ReceiverValue,
|
||||
topLevelScope: FirScope,
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ class FirTowerResolver(
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
scope,
|
||||
dispatchReceiver,
|
||||
extensionReceiverValue = null
|
||||
givenExtensionReceiverOptions = emptyList()
|
||||
),
|
||||
context
|
||||
)
|
||||
|
||||
@@ -40,9 +40,11 @@ sealed class TowerGroupKind(val index: Byte) : Comparable<TowerGroupKind> {
|
||||
|
||||
class ImplicitOrNonLocal(depth: Int, val kindForDebugSake: String) : WithDepth(6, depth)
|
||||
|
||||
object InvokeExtension : TowerGroupKind(7)
|
||||
class ContextReceiverGroup(depth: Int) : WithDepth(7, depth)
|
||||
|
||||
object QualifierValue : TowerGroupKind(8)
|
||||
object InvokeExtension : TowerGroupKind(8)
|
||||
|
||||
object QualifierValue : TowerGroupKind(9)
|
||||
|
||||
class UnqualifiedEnum(depth: Int) : WithDepth(9, depth)
|
||||
|
||||
@@ -166,6 +168,8 @@ private constructor(
|
||||
fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth))
|
||||
fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth))
|
||||
|
||||
fun ContextReceiverGroup(depth: Int) = kindOf(TowerGroupKind.ContextReceiverGroup(depth))
|
||||
|
||||
fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth))
|
||||
|
||||
val Last = kindOf(TowerGroupKind.Last)
|
||||
@@ -180,6 +184,8 @@ private constructor(
|
||||
fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth))
|
||||
fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth))
|
||||
|
||||
fun ContextReceiverGroup(depth: Int) = kindOf(TowerGroupKind.ContextReceiverGroup(depth))
|
||||
|
||||
val InvokeExtension get() = kindOf(TowerGroupKind.InvokeExtension)
|
||||
|
||||
fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth))
|
||||
|
||||
+3
-3
@@ -45,7 +45,7 @@ internal class TowerLevelHandler {
|
||||
CallKind.VariableAccess -> {
|
||||
processResult += towerLevel.processPropertiesByName(info, processor)
|
||||
|
||||
if (!collector.isSuccess() && towerLevel is ScopeTowerLevel && towerLevel.extensionReceiver == null) {
|
||||
if (!collector.isSuccess() && towerLevel is ScopeTowerLevel && !towerLevel.areThereExtensionReceiverOptions()) {
|
||||
processResult += towerLevel.processObjectsByName(info, processor)
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ private class TowerScopeLevelProcessor(
|
||||
override fun consumeCandidate(
|
||||
symbol: FirBasedSymbol<*>,
|
||||
dispatchReceiverValue: ReceiverValue?,
|
||||
extensionReceiverValue: ReceiverValue?,
|
||||
givenExtensionReceiverOptions: List<ReceiverValue>,
|
||||
scope: FirScope,
|
||||
objectsByName: Boolean
|
||||
) {
|
||||
@@ -85,7 +85,7 @@ private class TowerScopeLevelProcessor(
|
||||
explicitReceiverKind,
|
||||
scope,
|
||||
dispatchReceiverValue,
|
||||
extensionReceiverValue,
|
||||
givenExtensionReceiverOptions,
|
||||
objectsByName
|
||||
), candidateFactory.context
|
||||
)
|
||||
|
||||
+56
-32
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
@@ -56,7 +57,7 @@ abstract class TowerScopeLevel {
|
||||
fun consumeCandidate(
|
||||
symbol: T,
|
||||
dispatchReceiverValue: ReceiverValue?,
|
||||
extensionReceiverValue: ReceiverValue?,
|
||||
givenExtensionReceiverOptions: List<ReceiverValue>,
|
||||
scope: FirScope,
|
||||
objectsByName: Boolean = false
|
||||
)
|
||||
@@ -73,7 +74,7 @@ abstract class TowerScopeLevel {
|
||||
class MemberScopeTowerLevel(
|
||||
private val bodyResolveComponents: BodyResolveComponents,
|
||||
val dispatchReceiverValue: ReceiverValue,
|
||||
private val extensionReceiver: ReceiverValue? = null,
|
||||
private val givenExtensionReceiverOptions: List<ReceiverValue>,
|
||||
) : TowerScopeLevel() {
|
||||
private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession
|
||||
private val session: FirSession get() = bodyResolveComponents.session
|
||||
@@ -86,11 +87,11 @@ class MemberScopeTowerLevel(
|
||||
var (empty, candidates) = scope.collectCandidates(processScopeMembers)
|
||||
consumeCandidates(output, candidates.map { scope to it })
|
||||
|
||||
if (extensionReceiver == null) {
|
||||
if (givenExtensionReceiverOptions.isEmpty()) {
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope)
|
||||
withSynthetic.processScopeMembers { symbol ->
|
||||
empty = false
|
||||
output.consumeCandidate(symbol, dispatchReceiverValue, null, scope)
|
||||
output.consumeCandidate(symbol, dispatchReceiverValue, givenExtensionReceiverOptions = emptyList(), scope)
|
||||
}
|
||||
}
|
||||
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
|
||||
@@ -103,7 +104,7 @@ class MemberScopeTowerLevel(
|
||||
val result = mutableListOf<T>()
|
||||
processScopeMembers { candidate ->
|
||||
empty = false
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) {
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
||||
val fir = candidate.fir
|
||||
if ((fir as? FirConstructor)?.isInner == false) {
|
||||
return@processScopeMembers
|
||||
@@ -121,14 +122,14 @@ class MemberScopeTowerLevel(
|
||||
candidatesWithScope: List<Pair<FirScope, T>>
|
||||
) {
|
||||
for ((scope, candidate) in candidatesWithScope) {
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) {
|
||||
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
||||
output.consumeCandidate(
|
||||
candidate, dispatchReceiverValue,
|
||||
extensionReceiverValue = extensionReceiver,
|
||||
givenExtensionReceiverOptions,
|
||||
scope
|
||||
)
|
||||
} else if (candidate is FirClassLikeSymbol<*>) {
|
||||
output.consumeCandidate(candidate, null, extensionReceiver, scope)
|
||||
output.consumeCandidate(candidate, null, givenExtensionReceiverOptions, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,8 +202,30 @@ class MemberScopeTowerLevel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(extensionReceiver: Receiver?): Boolean {
|
||||
return (extensionReceiver != null) == hasExtensionReceiver()
|
||||
private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(givenExtensionReceivers: List<ReceiverValue>): Boolean {
|
||||
return givenExtensionReceivers.isNotEmpty() == hasExtensionReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
class ContextReceiverGroupMemberScopeTowerLevel(
|
||||
bodyResolveComponents: BodyResolveComponents,
|
||||
contextReceiverGroup: ContextReceiverGroup,
|
||||
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
|
||||
) : TowerScopeLevel() {
|
||||
private val memberScopeLevels = contextReceiverGroup.map {
|
||||
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions)
|
||||
}
|
||||
|
||||
override fun processFunctionsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>): ProcessResult {
|
||||
return memberScopeLevels.minOf { it.processFunctionsByName(info, processor) }
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirVariableSymbol<*>>): ProcessResult {
|
||||
return memberScopeLevels.minOf { it.processPropertiesByName(info, processor) }
|
||||
}
|
||||
|
||||
override fun processObjectsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirBasedSymbol<*>>): ProcessResult {
|
||||
return memberScopeLevels.minOf { it.processObjectsByName(info, processor) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,12 +239,14 @@ class MemberScopeTowerLevel(
|
||||
class ScopeTowerLevel(
|
||||
private val bodyResolveComponents: BodyResolveComponents,
|
||||
val scope: FirScope,
|
||||
val extensionReceiver: ReceiverValue?,
|
||||
private val givenExtensionReceiverOptions: List<ReceiverValue>,
|
||||
private val withHideMembersOnly: Boolean,
|
||||
private val includeInnerConstructors: Boolean
|
||||
) : TowerScopeLevel() {
|
||||
private val session: FirSession get() = bodyResolveComponents.session
|
||||
|
||||
fun areThereExtensionReceiverOptions(): Boolean = givenExtensionReceiverOptions.isNotEmpty()
|
||||
|
||||
private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>): ReceiverValue? {
|
||||
candidate.fir.importedFromObjectData?.let { data ->
|
||||
val objectClassId = data.objectClassId
|
||||
@@ -257,26 +282,25 @@ class ScopeTowerLevel(
|
||||
|
||||
private fun shouldSkipCandidateWithInconsistentExtensionReceiver(candidate: FirCallableSymbol<*>): Boolean {
|
||||
// Pre-check explicit extension receiver for default package top-level members
|
||||
if (scope is FirDefaultStarImportingScope && extensionReceiver != null) {
|
||||
if (scope !is FirDefaultStarImportingScope || !areThereExtensionReceiverOptions()) return false
|
||||
|
||||
val declarationReceiverType = candidate.resolvedReceiverTypeRef?.coneType as? ConeClassLikeType ?: return false
|
||||
val startProjectedDeclarationReceiverType = declarationReceiverType.lookupTag.constructClassType(
|
||||
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = true
|
||||
)
|
||||
|
||||
return givenExtensionReceiverOptions.none { extensionReceiver ->
|
||||
val extensionReceiverType = extensionReceiver.type
|
||||
if (extensionReceiverType is ConeClassLikeType) {
|
||||
val declarationReceiverType = candidate.resolvedReceiverTypeRef?.coneType
|
||||
if (declarationReceiverType is ConeClassLikeType) {
|
||||
if (!AbstractTypeChecker.isSubtypeOf(
|
||||
session.typeContext,
|
||||
extensionReceiverType,
|
||||
declarationReceiverType.lookupTag.constructClassType(
|
||||
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = true
|
||||
)
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
// If some receiver is non class like, we should not skip it
|
||||
if (extensionReceiverType !is ConeClassLikeType) return@none true
|
||||
|
||||
AbstractTypeChecker.isSubtypeOf(
|
||||
session.typeContext,
|
||||
extensionReceiverType,
|
||||
startProjectedDeclarationReceiverType
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun <T : FirBasedSymbol<*>> consumeCallableCandidate(
|
||||
@@ -287,7 +311,7 @@ class ScopeTowerLevel(
|
||||
if (withHideMembersOnly && candidate.getAnnotationByClassId(HidesMembers) == null) {
|
||||
return
|
||||
}
|
||||
val receiverExpected = withHideMembersOnly || extensionReceiver != null
|
||||
val receiverExpected = withHideMembersOnly || areThereExtensionReceiverOptions()
|
||||
if (candidateReceiverTypeRef == null == receiverExpected) return
|
||||
val dispatchReceiverValue = dispatchReceiverValue(candidate)
|
||||
if (dispatchReceiverValue == null && shouldSkipCandidateWithInconsistentExtensionReceiver(candidate)) {
|
||||
@@ -297,7 +321,7 @@ class ScopeTowerLevel(
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
processor.consumeCandidate(
|
||||
unwrappedCandidate as T, dispatchReceiverValue,
|
||||
extensionReceiverValue = extensionReceiver,
|
||||
givenExtensionReceiverOptions,
|
||||
scope
|
||||
)
|
||||
}
|
||||
@@ -343,7 +367,7 @@ class ScopeTowerLevel(
|
||||
empty = false
|
||||
processor.consumeCandidate(
|
||||
it, dispatchReceiverValue = null,
|
||||
extensionReceiverValue = null,
|
||||
givenExtensionReceiverOptions = emptyList(),
|
||||
scope = scope,
|
||||
objectsByName = true
|
||||
)
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ class FirBuilderInferenceSession(
|
||||
}
|
||||
|
||||
private fun Candidate.isSuitableForBuilderInference(): Boolean {
|
||||
val extensionReceiver = extensionReceiverValue
|
||||
val extensionReceiver = chosenExtensionReceiverValue
|
||||
val dispatchReceiver = dispatchReceiverValue
|
||||
return when {
|
||||
extensionReceiver == null && dispatchReceiver == null -> false
|
||||
|
||||
+15
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -259,6 +261,7 @@ class FirCallCompleter(
|
||||
override fun analyzeAndGetLambdaReturnArguments(
|
||||
lambdaAtom: ResolvedLambdaAtom,
|
||||
receiverType: ConeKotlinType?,
|
||||
contextReceivers: List<ConeKotlinType>,
|
||||
parameters: List<ConeKotlinType>,
|
||||
expectedReturnType: ConeKotlinType?,
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
|
||||
@@ -307,6 +310,18 @@ class FirCallCompleter(
|
||||
}
|
||||
)
|
||||
|
||||
if (contextReceivers.isNotEmpty()) {
|
||||
lambdaArgument.replaceContextReceivers(
|
||||
contextReceivers.map { contextReceiverType ->
|
||||
buildContextReceiver {
|
||||
typeRef = buildResolvedTypeRef {
|
||||
type = contextReceiverType
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val lookupTracker = session.lookupTracker
|
||||
val fileSource = components.file.source
|
||||
lambdaArgument.valueParameters.forEachIndexed { index, parameter ->
|
||||
|
||||
+1
-2
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubsti
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent
|
||||
@@ -74,7 +73,7 @@ class FirDelegatedPropertyInferenceSession(
|
||||
if (callee.candidate.system.hasContradiction) return true
|
||||
|
||||
val hasStubType =
|
||||
callee.candidate.extensionReceiverValue?.type?.containsStubType() ?: false
|
||||
callee.candidate.chosenExtensionReceiverValue?.type?.containsStubType() ?: false
|
||||
|| callee.candidate.dispatchReceiverValue?.type?.containsStubType() ?: false
|
||||
|
||||
if (!hasStubType) {
|
||||
|
||||
+15
-1
@@ -51,10 +51,16 @@ fun extractLambdaInfoFromFunctionalType(
|
||||
// For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter
|
||||
// can never fill its role.
|
||||
val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType
|
||||
val contextReceiversNumber =
|
||||
if (argument.isLambda) expectedType.contextReceiversNumberForFunctionType else argument.contextReceivers.size
|
||||
|
||||
val valueParametersTypesIncludingReceiver = expectedType.valueParameterTypesIncludingReceiver(session)
|
||||
val isExtensionFunctionType = expectedType.isExtensionFunctionType(session)
|
||||
val expectedParameters = valueParametersTypesIncludingReceiver.let {
|
||||
if (receiverType != null && isExtensionFunctionType) it.drop(1) else it
|
||||
val forExtension = if (receiverType != null && isExtensionFunctionType) 1 else 0
|
||||
val toDrop = forExtension + contextReceiversNumber
|
||||
|
||||
if (toDrop > 0) it.drop(toDrop) else it
|
||||
}
|
||||
|
||||
var coerceFirstParameterToExtensionReceiver = false
|
||||
@@ -84,11 +90,19 @@ fun extractLambdaInfoFromFunctionalType(
|
||||
}
|
||||
}
|
||||
|
||||
val contextReceivers =
|
||||
when {
|
||||
contextReceiversNumber == 0 -> emptyList()
|
||||
argument.isLambda -> valueParametersTypesIncludingReceiver.subList(0, contextReceiversNumber)
|
||||
else -> argument.contextReceivers.map { it.typeRef.coneType }
|
||||
}
|
||||
|
||||
return ResolvedLambdaAtom(
|
||||
argument,
|
||||
expectedType,
|
||||
expectedType.isSuspendFunctionType(session),
|
||||
receiverType,
|
||||
contextReceivers,
|
||||
parameters,
|
||||
returnType,
|
||||
typeVariableForLambdaReturnType = returnTypeVariable,
|
||||
|
||||
+7
-1
@@ -66,7 +66,8 @@ fun Candidate.preprocessLambdaArgument(
|
||||
if (resolvedArgument.coerceFirstParameterToExtensionReceiver) parameters.drop(1) else parameters,
|
||||
resolvedArgument.receiver,
|
||||
resolvedArgument.returnType,
|
||||
isSuspend = resolvedArgument.isSuspend
|
||||
isSuspend = resolvedArgument.isSuspend,
|
||||
contextReceivers = resolvedArgument.contextReceivers,
|
||||
)
|
||||
|
||||
val position = ConeArgumentConstraintPosition(resolvedArgument.atom)
|
||||
@@ -124,6 +125,10 @@ private fun extractLambdaInfo(
|
||||
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
|
||||
}
|
||||
|
||||
val contextReceivers = argument.contextReceivers.map {
|
||||
it.typeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
|
||||
}
|
||||
|
||||
val newTypeVariableUsed = returnType == typeVariable.defaultType
|
||||
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
|
||||
|
||||
@@ -132,6 +137,7 @@ private fun extractLambdaInfo(
|
||||
expectedType,
|
||||
isSuspend,
|
||||
receiverType,
|
||||
contextReceivers,
|
||||
parameters,
|
||||
returnType,
|
||||
typeVariable.takeIf { newTypeVariableUsed },
|
||||
|
||||
+3
@@ -37,6 +37,7 @@ interface LambdaAnalyzer {
|
||||
fun analyzeAndGetLambdaReturnArguments(
|
||||
lambdaAtom: ResolvedLambdaAtom,
|
||||
receiverType: ConeKotlinType?,
|
||||
contextReceivers: List<ConeKotlinType>,
|
||||
parameters: List<ConeKotlinType>,
|
||||
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
|
||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
|
||||
@@ -122,6 +123,7 @@ class PostponedArgumentsAnalyzer(
|
||||
fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType
|
||||
|
||||
val receiver = lambda.receiver?.let(::substitute)
|
||||
val contextReceivers = lambda.contextReceivers.map(::substitute)
|
||||
val parameters = lambda.parameters.map(::substitute)
|
||||
val rawReturnType = lambda.returnType
|
||||
|
||||
@@ -137,6 +139,7 @@ class PostponedArgumentsAnalyzer(
|
||||
val results = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments(
|
||||
lambda,
|
||||
receiver,
|
||||
contextReceivers,
|
||||
parameters,
|
||||
expectedTypeForReturnArguments,
|
||||
stubsForPostponedVariables,
|
||||
|
||||
@@ -41,6 +41,7 @@ class ResolvedLambdaAtom(
|
||||
expectedType: ConeKotlinType?,
|
||||
val isSuspend: Boolean,
|
||||
val receiver: ConeKotlinType?,
|
||||
val contextReceivers: List<ConeKotlinType>,
|
||||
val parameters: List<ConeKotlinType>,
|
||||
var returnType: ConeKotlinType,
|
||||
typeVariableForLambdaReturnType: ConeTypeVariableForLambdaReturnType?,
|
||||
|
||||
+3
-3
@@ -467,8 +467,8 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
||||
|
||||
private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType {
|
||||
val parameters =
|
||||
listOfNotNull(typeRef.receiverTypeRef?.coneType) +
|
||||
typeRef.contextReceiverTypeRefs.map { it.coneType } +
|
||||
typeRef.contextReceiverTypeRefs.map { it.coneType } +
|
||||
listOfNotNull(typeRef.receiverTypeRef?.coneType) +
|
||||
typeRef.valueParameters.map { it.returnTypeRef.coneType.withParameterNameAnnotation(it) } +
|
||||
listOf(typeRef.returnTypeRef.coneType)
|
||||
val classId = if (typeRef.isSuspend) {
|
||||
@@ -550,7 +550,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
||||
override val dispatchReceiverValue: ReceiverValue?
|
||||
get() = null
|
||||
|
||||
override val extensionReceiverValue: ReceiverValue?
|
||||
override val chosenExtensionReceiverValue: ReceiverValue?
|
||||
get() = null
|
||||
|
||||
override val explicitReceiverKind: ExplicitReceiverKind
|
||||
|
||||
+2
-2
@@ -131,7 +131,7 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
}
|
||||
|
||||
var dispatchReceiver = subCandidate.dispatchReceiverExpression()
|
||||
var extensionReceiver = subCandidate.extensionReceiverExpression()
|
||||
var extensionReceiver = subCandidate.chosenExtensionReceiverExpression()
|
||||
if (!declaration.isWrappedIntegerOperator()) {
|
||||
val expectedDispatchReceiverType = (declaration as? FirCallableDeclaration)?.dispatchReceiverType
|
||||
val expectedExtensionReceiverType = (declaration as? FirCallableDeclaration)?.receiverTypeRef?.coneType
|
||||
@@ -403,7 +403,7 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
StoreCalleeReference,
|
||||
resolvedReference,
|
||||
).transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression())
|
||||
.transformExtensionReceiver(StoreReceiver, subCandidate.extensionReceiverExpression())
|
||||
.transformExtensionReceiver(StoreReceiver, subCandidate.chosenExtensionReceiverExpression())
|
||||
}
|
||||
|
||||
override fun transformVariableAssignment(
|
||||
|
||||
+3
-1
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
@@ -228,6 +227,8 @@ class BodyResolveContext(
|
||||
holder: SessionHolder,
|
||||
f: () -> T
|
||||
): T = withTowerDataCleanup {
|
||||
replaceTowerDataContext(towerDataContext.addContextReceiverGroup(owner.createContextReceiverValues(holder)))
|
||||
|
||||
if (type != null) {
|
||||
val receiver = ImplicitExtensionReceiverValue(
|
||||
owner.symbol,
|
||||
@@ -450,6 +451,7 @@ class BodyResolveContext(
|
||||
val forMembersResolution =
|
||||
staticsAndCompanion
|
||||
.addReceiver(labelName, towerElementsForClass.thisReceiver)
|
||||
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
|
||||
.addNonLocalScopeIfNotNull(typeParameterScope)
|
||||
|
||||
val scopeForConstructorHeader =
|
||||
|
||||
+14
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunctionCopy
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
@@ -34,7 +35,6 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrIni
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType
|
||||
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||
@@ -809,6 +809,19 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
lambda = buildAnonymousFunctionCopy(lambda) {
|
||||
receiverTypeRef = lambda.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef }
|
||||
?: resolvedLambdaAtom?.receiver?.let { lambda.receiverTypeRef?.resolvedTypeFromPrototype(it) }
|
||||
|
||||
contextReceivers.clear()
|
||||
contextReceivers.addAll(
|
||||
lambda.contextReceivers.takeIf { it.isNotEmpty() }
|
||||
?: resolvedLambdaAtom?.contextReceivers?.map { receiverType ->
|
||||
buildContextReceiver {
|
||||
this.typeRef = buildResolvedTypeRef {
|
||||
type = receiverType
|
||||
}
|
||||
}
|
||||
}.orEmpty()
|
||||
)
|
||||
|
||||
this.valueParameters.clear()
|
||||
this.valueParameters.addAll(valueParameters)
|
||||
returnTypeRef = (lambda.returnTypeRef as? FirResolvedTypeRef)
|
||||
|
||||
Reference in New Issue
Block a user