diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirTowerDataContextCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirTowerDataContextCollector.kt index 4fce3013272..3126a761cf8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirTowerDataContextCollector.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirTowerDataContextCollector.kt @@ -37,7 +37,8 @@ internal class FirTowerDataContextAllElementsCollector : FirTowerDataContextColl override fun addStatementContext(statement: FirStatement, context: FirTowerDataContext) { val closestStatementInBlock = statement.psi?.closestBlockLevelOrInitializerExpression() ?: return - elementsToContext[closestStatementInBlock] = context + // FIR body transform may alter the context if there are implicit receivers with smartcast + elementsToContext[closestStatementInBlock] = context.createSnapshot() } override fun addDeclarationContext(declaration: FirDeclaration, context: FirTowerDataContext) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt index 166a6c473bd..2fbc7ad04a7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import org.jetbrains.kotlin.fir.FirCallResolver import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* @@ -137,6 +138,16 @@ class FirTowerDataContext private constructor( nonLocalTowerDataElements.add(element) ) } + + fun createSnapshot(): FirTowerDataContext { + return FirTowerDataContext( + towerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) }.toPersistentList(), + implicitReceiverStack.createSnapshot(), + localScopes.toPersistentList(), + nonLocalTowerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) } + .toPersistentList() + ) + } } class FirTowerDataElement(val scope: FirScope?, val implicitReceiver: ImplicitReceiverValue<*>?, val isLocal: Boolean) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt index dd3184ddc6a..be1b2822460 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.fir.resolve -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.PersistentMap -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.* import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -84,4 +81,13 @@ class PersistentImplicitReceiverStack private constructor( assert(index >= 0 && index < stack.size) stack[index].replaceType(type) } + + fun createSnapshot(): PersistentImplicitReceiverStack { + return PersistentImplicitReceiverStack( + stack.map { it.createSnapshot() }.toPersistentList(), + indexesPerLabel, + indexesPerSymbol, + originalTypes + ) + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index 7e67e16e1e8..15143d87b4f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -73,7 +73,8 @@ sealed class ImplicitReceiverValue>( val boundSymbol: S, type: ConeKotlinType, protected val useSiteSession: FirSession, - protected val scopeSession: ScopeSession + protected val scopeSession: ScopeSession, + private val mutable: Boolean, ) : ReceiverValue { final override var type: ConeKotlinType = type private set @@ -93,6 +94,7 @@ sealed class ImplicitReceiverValue>( * Should be called only in ImplicitReceiverStack */ internal fun replaceType(type: ConeKotlinType) { + if (!mutable) throw IllegalStateException("Cannot mutate an immutable ImplicitReceiverValue") if (type == this.type) return this.type = type receiverExpression = if (type == originalReceiverExpression.typeRef.coneType) { @@ -107,6 +109,8 @@ sealed class ImplicitReceiverValue>( } implicitScope = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing) } + + abstract fun createSnapshot(): ImplicitReceiverValue } private fun receiverExpression(symbol: FirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression = @@ -126,27 +130,42 @@ class ImplicitDispatchReceiverValue internal constructor( boundSymbol: FirClassSymbol<*>, type: ConeKotlinType, useSiteSession: FirSession, - scopeSession: ScopeSession -) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession) { + scopeSession: ScopeSession, + mutable: Boolean = true, +) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession, mutable) { internal constructor( boundSymbol: FirClassSymbol<*>, useSiteSession: FirSession, scopeSession: ScopeSession ) : this( boundSymbol, boundSymbol.constructType(typeArguments = emptyArray(), isNullable = false), useSiteSession, scopeSession ) + + override fun createSnapshot(): ImplicitReceiverValue> { + return ImplicitDispatchReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) + } } class ImplicitExtensionReceiverValue( boundSymbol: FirCallableSymbol<*>, type: ConeKotlinType, useSiteSession: FirSession, - scopeSession: ScopeSession -) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession) + scopeSession: ScopeSession, + mutable: Boolean = true, +) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession, mutable) { + override fun createSnapshot(): ImplicitReceiverValue> { + return ImplicitExtensionReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) + } +} class InaccessibleImplicitReceiverValue( boundSymbol: FirClassSymbol<*>, type: ConeKotlinType, useSiteSession: FirSession, - scopeSession: ScopeSession -) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession) + scopeSession: ScopeSession, + mutable: Boolean = true, +) : ImplicitReceiverValue>(boundSymbol, type, useSiteSession, scopeSession, mutable) { + override fun createSnapshot(): ImplicitReceiverValue> { + return InaccessibleImplicitReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) + } +}