
org.jetbrains.kotlin.fir.resolve.ImplicitValueStorage.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve
import kotlinx.collections.immutable.*
import org.jetbrains.kotlin.fir.declarations.FirTowerDataElement
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirThisOwnerSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.util.PersistentSetMultimap
import org.jetbrains.kotlin.name.Name
class ImplicitValueStorage private constructor(
private val implicitReceiverStack: PersistentList>,
private val implicitReceiversByLabel: PersistentSetMultimap>,
private val implicitValuesBySymbol: PersistentMap, ImplicitValue>
) {
constructor() : this(
persistentListOf(),
PersistentSetMultimap(),
persistentMapOf(),
)
val implicitReceivers: List>
get() = implicitReceiverStack
/**
* Contains implicit receivers, context receivers and context parameters.
* Only used by DFA to apply smart casts using [ImplicitValueStorage.replaceImplicitValueType].
* Therefore, it's just a helper and [FirTowerDataElement] should be considered the actual source of truth.
*/
@ImplicitValue.ImplicitValueInternals
val implicitValues: Collection
get() = implicitValuesBySymbol.values
fun addAllImplicitReceivers(receivers: List>): ImplicitValueStorage {
return receivers.fold(this) { acc, value -> acc.addImplicitReceiver(name = null, value) }
}
fun addImplicitReceiver(name: Name?, value: ImplicitReceiverValue<*>, aliasLabel: Name? = null): ImplicitValueStorage {
val stack = implicitReceiverStack.add(value)
val receiversPerLabel = implicitReceiversByLabel.putIfNameIsNotNull(name, value).putIfNameIsNotNull(aliasLabel, value)
val implicitValuesBySymbol = implicitValuesBySymbol.put(value.boundSymbol, value)
return ImplicitValueStorage(
stack,
receiversPerLabel,
implicitValuesBySymbol,
)
}
fun addAllContexts(
contextReceivers: List,
contextParameters: List,
): ImplicitValueStorage {
if (contextReceivers.isEmpty() && contextParameters.isEmpty()) {
return this
}
// Not adding context receivers to implicitValuesBySymbol is a bug that leads to smart-casts not working.
// However, we're leaving it broken because context receivers are getting removed anyway.
return ImplicitValueStorage(
implicitReceiverStack,
contextReceivers.fold(implicitReceiversByLabel) { acc, value -> acc.putIfNameIsNotNull(value.labelName, value) },
contextParameters.fold(implicitValuesBySymbol) { acc, value -> acc.put(value.boundSymbol, value) },
)
}
private fun PersistentSetMultimap>.putIfNameIsNotNull(name: Name?, value: ImplicitReceiverValue<*>) =
if (name != null)
put(name, value)
else
this
operator fun get(name: String?): Set> {
if (name == null) return implicitReceiverStack.lastOrNull()?.let(::setOf).orEmpty()
return implicitReceiversByLabel[Name.identifier(name)]
}
fun lastDispatchReceiver(): ImplicitDispatchReceiverValue? {
return implicitReceiverStack.filterIsInstance().lastOrNull()
}
fun lastDispatchReceiver(lookupCondition: (ImplicitReceiverValue<*>) -> Boolean): ImplicitDispatchReceiverValue? {
return implicitReceiverStack.filterIsInstance().lastOrNull(lookupCondition)
}
fun receiversAsReversed(): List> = implicitReceiverStack.asReversed()
/**
* Applies smart-casted type to an [ImplicitValue] identified by its [symbol].
*
* Only used by DFA, and in some sense breaks persistence contracts of the data structure.
* Therefore, it's a very fragile API and maybe should be rewritten somehow.
*/
@ImplicitValue.ImplicitValueInternals
fun replaceImplicitValueType(symbol: FirBasedSymbol<*>, type: ConeKotlinType) {
val implicitValue = implicitValuesBySymbol[symbol as FirThisOwnerSymbol<*>] ?: return
implicitValue.updateTypeFromSmartcast(type)
}
fun createSnapshot(keepMutable: Boolean): ImplicitValueStorage {
return ImplicitValueStorage(
implicitReceiverStack.map { it.createSnapshot(keepMutable) }.toPersistentList(),
implicitReceiversByLabel,
implicitValuesBySymbol,
)
}
}
fun Set>.singleWithoutDuplicatingContextReceiversOrNull(): ImplicitReceiverValue<*>? {
// KT-69102: we may encounter a bug with duplicated context receivers, and it wasn't obvious how to fix it
return distinctBy { if (it.isContextReceiver) it.boundSymbol else it }.singleOrNull()
}
fun Set>.ambiguityDiagnosticFor(labelName: String?): ConeSimpleDiagnostic {
// This condition helps choose between an error diagnostic and a warning one to better
// replicate the K1 behavior and avoid breaking changes.
val areAlmostAllAnonymousFunctions = count {
it.referencedMemberSymbol is FirAnonymousFunctionSymbol
} >= size - 1
val diagnostic = when {
areAlmostAllAnonymousFunctions -> ConeSimpleDiagnostic("Clashing this@$labelName", DiagnosticKind.LabelNameClash)
else -> ConeSimpleDiagnostic("Ambiguous this@$labelName", DiagnosticKind.AmbiguousLabel)
}
return diagnostic
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy