FIR: Add preliminary support for context receivers in resolution
This commit is contained in:
+70
-18
@@ -8,14 +8,14 @@ package org.jetbrains.kotlin.fir.declarations
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import org.jetbrains.kotlin.fir.labelName
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -23,32 +23,39 @@ fun SessionHolder.collectImplicitReceivers(
|
||||
type: ConeKotlinType?,
|
||||
owner: FirDeclaration
|
||||
): ImplicitReceivers {
|
||||
if (type == null) return ImplicitReceivers(null, emptyList())
|
||||
|
||||
val implicitCompanionValues = mutableListOf<ImplicitReceiverValue<*>>()
|
||||
val contextReceiverValues = mutableListOf<ContextReceiverValue<*>>()
|
||||
val implicitReceiverValue = when (owner) {
|
||||
is FirClass -> {
|
||||
val towerElementsForClass = collectTowerDataElementsForClass(owner, type)
|
||||
val towerElementsForClass = collectTowerDataElementsForClass(owner, type!!)
|
||||
implicitCompanionValues.addAll(towerElementsForClass.implicitCompanionValues)
|
||||
contextReceiverValues.addAll(towerElementsForClass.contextReceivers)
|
||||
|
||||
towerElementsForClass.thisReceiver
|
||||
}
|
||||
is FirFunction -> {
|
||||
ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession)
|
||||
contextReceiverValues.addAll(owner.createContextReceiverValues(this))
|
||||
type?.let { ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) }
|
||||
}
|
||||
is FirVariable -> {
|
||||
ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession)
|
||||
contextReceiverValues.addAll(owner.createContextReceiverValues(this))
|
||||
type?.let { ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) }
|
||||
}
|
||||
else -> {
|
||||
throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
|
||||
if (type != null) {
|
||||
throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
|
||||
}
|
||||
|
||||
null
|
||||
}
|
||||
}
|
||||
return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues)
|
||||
return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues, contextReceiverValues)
|
||||
}
|
||||
|
||||
data class ImplicitReceivers(
|
||||
val implicitReceiverValue: ImplicitReceiverValue<*>?,
|
||||
val implicitCompanionValues: List<ImplicitReceiverValue<*>>
|
||||
val implicitCompanionValues: List<ImplicitReceiverValue<*>>,
|
||||
val contextReceivers: List<ContextReceiverValue<*>>,
|
||||
)
|
||||
|
||||
fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType: ConeKotlinType): TowerElementsForClass {
|
||||
@@ -83,9 +90,15 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType:
|
||||
}
|
||||
|
||||
val thisReceiver = ImplicitDispatchReceiverValue(owner.symbol, defaultType, session, scopeSession)
|
||||
val contextReceivers = (owner as? FirRegularClass)?.contextReceivers?.map {
|
||||
ContextReceiverValueForClass(
|
||||
owner.symbol, it.typeRef.coneType, it.labelName, session, scopeSession,
|
||||
)
|
||||
}.orEmpty()
|
||||
|
||||
return TowerElementsForClass(
|
||||
thisReceiver,
|
||||
contextReceivers,
|
||||
owner.staticScope(this),
|
||||
companionReceiver,
|
||||
companionObject?.staticScope(this),
|
||||
@@ -96,6 +109,7 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType:
|
||||
|
||||
class TowerElementsForClass(
|
||||
val thisReceiver: ImplicitReceiverValue<*>,
|
||||
val contextReceivers: List<ContextReceiverValueForClass>,
|
||||
val staticScope: FirScope?,
|
||||
val companionReceiver: ImplicitReceiverValue<*>?,
|
||||
val companionStaticScope: FirScope?,
|
||||
@@ -137,7 +151,9 @@ class FirTowerDataContext private constructor(
|
||||
fun addNonLocalTowerDataElements(newElements: List<FirTowerDataElement>): FirTowerDataContext {
|
||||
return FirTowerDataContext(
|
||||
towerDataElements.addAll(newElements),
|
||||
implicitReceiverStack.addAll(newElements.mapNotNull { it.implicitReceiver }),
|
||||
implicitReceiverStack
|
||||
.addAll(newElements.mapNotNull { it.implicitReceiver })
|
||||
.addAllContextReceivers(newElements.flatMap { it.contextReceiverGroup.orEmpty() }),
|
||||
localScopes,
|
||||
nonLocalTowerDataElements.addAll(newElements)
|
||||
)
|
||||
@@ -162,6 +178,18 @@ class FirTowerDataContext private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
fun addContextReceiverGroup(contextReceiverGroup: ContextReceiverGroup): FirTowerDataContext {
|
||||
if (contextReceiverGroup.isEmpty()) return this
|
||||
val element = contextReceiverGroup.asTowerDataElement()
|
||||
|
||||
return FirTowerDataContext(
|
||||
towerDataElements.add(element),
|
||||
contextReceiverGroup.fold(implicitReceiverStack, PersistentImplicitReceiverStack::addContextReceiver),
|
||||
localScopes,
|
||||
nonLocalTowerDataElements.add(element)
|
||||
)
|
||||
}
|
||||
|
||||
fun addNonLocalScopeIfNotNull(scope: FirScope?): FirTowerDataContext {
|
||||
if (scope == null) return this
|
||||
return addNonLocalScope(scope)
|
||||
@@ -179,23 +207,47 @@ class FirTowerDataContext private constructor(
|
||||
|
||||
fun createSnapshot(): FirTowerDataContext {
|
||||
return FirTowerDataContext(
|
||||
towerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) }.toPersistentList(),
|
||||
towerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList(),
|
||||
implicitReceiverStack.createSnapshot(),
|
||||
localScopes.toPersistentList(),
|
||||
nonLocalTowerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) }
|
||||
.toPersistentList()
|
||||
nonLocalTowerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class FirTowerDataElement(val scope: FirScope?, val implicitReceiver: ImplicitReceiverValue<*>?, val isLocal: Boolean)
|
||||
class FirTowerDataElement(
|
||||
val scope: FirScope?,
|
||||
val implicitReceiver: ImplicitReceiverValue<*>?,
|
||||
val contextReceiverGroup: ContextReceiverGroup? = null,
|
||||
val isLocal: Boolean,
|
||||
) {
|
||||
fun createSnapshot(): FirTowerDataElement =
|
||||
FirTowerDataElement(
|
||||
scope,
|
||||
implicitReceiver?.createSnapshot(),
|
||||
contextReceiverGroup?.map { it.createSnapshot() },
|
||||
isLocal,
|
||||
)
|
||||
}
|
||||
|
||||
fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement =
|
||||
FirTowerDataElement(scope = null, this, isLocal = false)
|
||||
FirTowerDataElement(scope = null, implicitReceiver = this, isLocal = false)
|
||||
|
||||
fun ContextReceiverGroup.asTowerDataElement(): FirTowerDataElement =
|
||||
FirTowerDataElement(scope = null, implicitReceiver = null, contextReceiverGroup = this, isLocal = false)
|
||||
|
||||
fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement =
|
||||
FirTowerDataElement(this, implicitReceiver = null, isLocal)
|
||||
FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = isLocal)
|
||||
|
||||
fun FirClass.staticScope(sessionHolder: SessionHolder) =
|
||||
scopeProvider.getStaticScope(this, sessionHolder.session, sessionHolder.scopeSession)
|
||||
|
||||
typealias ContextReceiverGroup = List<ContextReceiverValue<*>>
|
||||
typealias FirLocalScopes = PersistentList<FirLocalScope>
|
||||
|
||||
fun FirCallableDeclaration.createContextReceiverValues(
|
||||
sessionHolder: SessionHolder,
|
||||
): List<ContextReceiverValueForCallable> =
|
||||
contextReceivers.map {
|
||||
ContextReceiverValueForCallable(symbol, it.typeRef.coneType, it.labelName, sessionHolder.session, sessionHolder.scopeSession)
|
||||
}
|
||||
|
||||
+33
-6
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve
|
||||
|
||||
import kotlinx.collections.immutable.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ContextReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
class PersistentImplicitReceiverStack private constructor(
|
||||
private val stack: PersistentList<ImplicitReceiverValue<*>>,
|
||||
// This multi-map holds indexes of the stack ^
|
||||
private val indexesPerLabel: PersistentSetMultimap<Name, Int>,
|
||||
private val receiversPerLabel: PersistentSetMultimap<Name, ImplicitReceiverValue<*>>,
|
||||
private val indexesPerSymbol: PersistentMap<FirBasedSymbol<*>, Int>,
|
||||
private val originalTypes: PersistentList<ConeKotlinType>,
|
||||
) : ImplicitReceiverStack(), Iterable<ImplicitReceiverValue<*>> {
|
||||
@@ -33,16 +34,42 @@ class PersistentImplicitReceiverStack private constructor(
|
||||
return receivers.fold(this) { acc, value -> acc.add(name = null, value) }
|
||||
}
|
||||
|
||||
fun add(name: Name?, value: ImplicitReceiverValue<*>): PersistentImplicitReceiverStack {
|
||||
fun addAllContextReceivers(receivers: List<ContextReceiverValue<*>>): PersistentImplicitReceiverStack {
|
||||
return receivers.fold(this) { acc, value -> acc.addContextReceiver(value) }
|
||||
}
|
||||
|
||||
fun add(name: Name?, value: ImplicitReceiverValue<*>, aliasLabel: Name? = null): PersistentImplicitReceiverStack {
|
||||
val stack = stack.add(value)
|
||||
val originalTypes = originalTypes.add(value.originalType)
|
||||
val index = stack.size - 1
|
||||
val indexesPerLabel = name?.let { indexesPerLabel.put(it, index) } ?: indexesPerLabel
|
||||
val receiversPerLabel = name?.let { receiversPerLabel.put(it, value) } ?: receiversPerLabel
|
||||
val indexesPerSymbol = indexesPerSymbol.put(value.boundSymbol, index)
|
||||
|
||||
return PersistentImplicitReceiverStack(
|
||||
stack,
|
||||
indexesPerLabel,
|
||||
receiversPerLabel,
|
||||
indexesPerSymbol,
|
||||
originalTypes
|
||||
)
|
||||
}
|
||||
|
||||
fun addContextReceiver(value: ContextReceiverValue<*>): PersistentImplicitReceiverStack {
|
||||
val labelName = value.labelName ?: return this
|
||||
|
||||
val receiversPerLabel = receiversPerLabel.put(labelName, value)
|
||||
return PersistentImplicitReceiverStack(
|
||||
stack,
|
||||
receiversPerLabel,
|
||||
indexesPerSymbol,
|
||||
originalTypes
|
||||
)
|
||||
}
|
||||
|
||||
fun addReceiverLabelAlias(aliasLabel: Name, value: ImplicitReceiverValue<*>): PersistentImplicitReceiverStack {
|
||||
val receiversPerLabel = receiversPerLabel.put(aliasLabel, value)
|
||||
return PersistentImplicitReceiverStack(
|
||||
stack,
|
||||
receiversPerLabel,
|
||||
indexesPerSymbol,
|
||||
originalTypes
|
||||
)
|
||||
@@ -50,7 +77,7 @@ class PersistentImplicitReceiverStack private constructor(
|
||||
|
||||
override operator fun get(name: String?): ImplicitReceiverValue<*>? {
|
||||
if (name == null) return stack.lastOrNull()
|
||||
return indexesPerLabel[Name.identifier(name)].lastOrNull()?.let { stack[it] }
|
||||
return receiversPerLabel[Name.identifier(name)].lastOrNull()
|
||||
}
|
||||
|
||||
override fun lastDispatchReceiver(): ImplicitDispatchReceiverValue? {
|
||||
@@ -85,7 +112,7 @@ class PersistentImplicitReceiverStack private constructor(
|
||||
fun createSnapshot(): PersistentImplicitReceiverStack {
|
||||
return PersistentImplicitReceiverStack(
|
||||
stack.map { it.createSnapshot() }.toPersistentList(),
|
||||
indexesPerLabel,
|
||||
receiversPerLabel,
|
||||
indexesPerSymbol,
|
||||
originalTypes
|
||||
)
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
abstract class AbstractCandidate {
|
||||
abstract val symbol: FirBasedSymbol<*>
|
||||
abstract val dispatchReceiverValue: ReceiverValue?
|
||||
abstract val extensionReceiverValue: ReceiverValue?
|
||||
abstract val chosenExtensionReceiverValue: ReceiverValue?
|
||||
abstract val explicitReceiverKind: ExplicitReceiverKind
|
||||
abstract val callInfo: AbstractCallInfo
|
||||
abstract val diagnostics: List<ResolutionDiagnostic>
|
||||
|
||||
+13
-2
@@ -82,7 +82,8 @@ object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RES
|
||||
|
||||
object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED)
|
||||
|
||||
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) : ResolutionDiagnostic(UNSTABLE_SMARTCAST)
|
||||
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) :
|
||||
ResolutionDiagnostic(UNSTABLE_SMARTCAST)
|
||||
|
||||
class ArgumentTypeMismatch(
|
||||
val expectedType: ConeKotlinType,
|
||||
@@ -107,4 +108,14 @@ class Unsupported(val message: String, val source: KtSourceElement? = null) : Re
|
||||
|
||||
object PropertyAsOperator : ResolutionDiagnostic(PROPERTY_AS_OPERATOR)
|
||||
|
||||
class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(DSL_SCOPE_VIOLATION)
|
||||
class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(DSL_SCOPE_VIOLATION)
|
||||
|
||||
class MultipleContextReceiversApplicableForExtensionReceivers : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
class NoApplicableValueForContextReceiver(
|
||||
val expectedContextReceiverType: ConeKotlinType
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
class AmbiguousValuesForContextReceiverParameter(
|
||||
val expectedContextReceiverType: ConeKotlinType,
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
Reference in New Issue
Block a user