[FIR2IR] Don't create IR constructors when their symbol is referenced

KT-62856
This commit is contained in:
Dmitriy Novozhilov
2023-11-14 17:12:04 +02:00
committed by Space Team
parent 55f62834cb
commit 65797e8fba
7 changed files with 107 additions and 127 deletions
@@ -238,13 +238,7 @@ class Fir2IrConverter(
irClass.declarations.addAll(classifierStorage.getFieldsWithContextReceiversForClass(irClass, klass))
val irConstructor = klass.primaryConstructorIfAny(session)?.let {
if (klass.classKind == ClassKind.ANNOTATION_CLASS) {
// TODO: this branch should be removed after fix of KT-62856
@OptIn(GetOrCreateSensitiveAPI::class)
declarationStorage.getOrCreateIrConstructor(it.fir, irClass, isLocal = klass.isLocal)
} else {
declarationStorage.createAndCacheIrConstructor(it.fir, { irClass }, isLocal = klass.isLocal)
}
declarationStorage.createAndCacheIrConstructor(it.fir, { irClass }, isLocal = klass.isLocal)
}
val delegateFieldToPropertyMap = MultiMap<FirProperty, FirField>()
@@ -573,13 +567,7 @@ class Fir2IrConverter(
}
is FirConstructor -> if (!declaration.isPrimary) {
// the primary constructor was already created in `processClassMembers` function
if (containingClass?.classKind == ClassKind.ANNOTATION_CLASS) {
// TODO: this branch should be removed after fix of KT-62856
@OptIn(GetOrCreateSensitiveAPI::class)
declarationStorage.getOrCreateIrConstructor(declaration, parent as IrClass, isLocal = isInLocalClass)
} else {
declarationStorage.createAndCacheIrConstructor(declaration, { parent as IrClass }, isLocal = isInLocalClass)
}
declarationStorage.createAndCacheIrConstructor(declaration, { parent as IrClass }, isLocal = isInLocalClass)
}
is FirEnumEntry -> {
classifierStorage.getOrCreateIrEnumEntry(declaration, parent as IrClass)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
@@ -29,10 +30,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.resolvedType
import org.jetbrains.kotlin.fir.types.toLookupTag
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.*
@@ -46,6 +44,7 @@ import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
@@ -364,37 +363,8 @@ class Fir2IrDeclarationStorage(
// ------------------------------------ constructors ------------------------------------
fun getCachedIrConstructorSymbol(
constructor: FirConstructor,
signatureCalculator: () -> IdSignature? = { null }
): IrConstructorSymbol? {
return constructorCache[constructor] ?: signatureCalculator()?.let { signature ->
symbolTable.referenceConstructorIfAny(signature)?.also { irConstructorSymbol ->
constructorCache[constructor] = irConstructorSymbol
}
}
}
@GetOrCreateSensitiveAPI
fun getOrCreateIrConstructor(
constructor: FirConstructor,
irParent: IrClass,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
): IrConstructor {
return getOrCreateIrConstructor(constructor, { irParent }, predefinedOrigin, isLocal)
}
@GetOrCreateSensitiveAPI
private fun getOrCreateIrConstructor(
constructor: FirConstructor,
irParent: () -> IrClass,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
): IrConstructor {
@OptIn(UnsafeDuringIrConstructionAPI::class)
getCachedIrConstructorSymbol(constructor)?.ownerIfBound()?.let { return it }
return createAndCacheIrConstructor(constructor, irParent, predefinedOrigin, isLocal)
fun getCachedIrConstructorSymbol(constructor: FirConstructor): IrConstructorSymbol? {
return constructorCache[constructor]
}
fun createAndCacheIrConstructor(
@@ -403,15 +373,13 @@ class Fir2IrDeclarationStorage(
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
): IrConstructor {
// caching of created constructor is not called here, because `callablesGenerator` calls `cacheIrConstructor` by itself
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(constructor)
}
val symbol = getIrConstructorSymbol(constructor.symbol, isLocal)
return callablesGenerator.createIrConstructor(
constructor,
irParent(),
createConstructorSymbol(signature),
predefinedOrigin
symbol,
predefinedOrigin,
allowLazyDeclarationsCreation = false
)
}
@@ -422,17 +390,39 @@ class Fir2IrDeclarationStorage(
}
}
@LeakedDeclarationCaches
internal fun cacheIrConstructor(constructor: FirConstructor, irConstructor: IrConstructor) {
constructorCache[constructor] = irConstructor.symbol
private fun cacheIrConstructorSymbol(constructor: FirConstructor, irConstructorSymbol: IrConstructorSymbol) {
constructorCache[constructor] = irConstructorSymbol
}
@OptIn(GetOrCreateSensitiveAPI::class)
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol {
val fir = firConstructorSymbol.fir
return getOrCreateIrConstructor(fir, { findIrParent(fir, fakeOverrideOwnerLookupTag = null) as IrClass }).symbol
}
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol, isLocal: Boolean = false): IrConstructorSymbol {
val constructor = firConstructorSymbol.fir
getCachedIrConstructorSymbol(constructor)?.let { return it }
// caching of created constructor is not called here, because `callablesGenerator` calls `cacheIrConstructor` by itself
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(constructor)
}
val symbol = createConstructorSymbol(signature)
if (!isLocal) {
val irParent = findIrParent(constructor, fakeOverrideOwnerLookupTag = null)
val isIntrinsicConstEvaluation =
constructor.returnTypeRef.coneType.classId == StandardClassIds.Annotations.IntrinsicConstEvaluation
if (irParent.isExternalParent() || isIntrinsicConstEvaluation) {
callablesGenerator.createIrConstructor(
constructor,
irParent as IrClass,
symbol,
constructor.computeExternalOrigin(),
allowLazyDeclarationsCreation = true
).also {
check(it is Fir2IrLazyConstructor || isIntrinsicConstEvaluation)
}
}
}
cacheIrConstructorSymbol(constructor, symbol)
return symbol
}
// ------------------------------------ properties ------------------------------------
@@ -987,39 +977,38 @@ class Fir2IrDeclarationStorage(
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
isLocal: Boolean = false
): IrFunctionSymbol {
return when (val function = firFunctionSymbol.fir) {
is FirConstructor -> {
getIrConstructorSymbol(function.symbol)
}
else -> {
getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.let { return it }
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(firFunctionSymbol.fir, fakeOverrideOwnerLookupTag)
}
val symbol = createFunctionSymbol(signature)
if (function is FirSimpleFunction && !isLocal) {
val irParent = findIrParent(function, fakeOverrideOwnerLookupTag)
if (irParent?.isExternalParent() == true) {
// Return value is not used here, because creation of IR declaration binds it to the corresponding symbol
// And all we want here is to bind symbol for lazy declaration
callablesGenerator.createIrFunction(
function,
irParent,
symbol,
predefinedOrigin = function.computeExternalOrigin(),
isLocal = false,
fakeOverrideOwnerLookupTag,
allowLazyDeclarationsCreation = true
).also {
check(it is Fir2IrLazySimpleFunction)
}
}
}
val function = firFunctionSymbol.fir
cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag)
return symbol
if (function is FirConstructor) {
return getIrConstructorSymbol(function.symbol)
}
getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.let { return it }
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(firFunctionSymbol.fir, fakeOverrideOwnerLookupTag)
}
val symbol = createFunctionSymbol(signature)
if (function is FirSimpleFunction && !isLocal) {
val irParent = findIrParent(function, fakeOverrideOwnerLookupTag)
if (irParent?.isExternalParent() == true) {
// Return value is not used here, because creation of IR declaration binds it to the corresponding symbol
// And all we want here is to bind symbol for lazy declaration
callablesGenerator.createIrFunction(
function,
irParent,
symbol,
predefinedOrigin = function.computeExternalOrigin(),
isLocal = false,
fakeOverrideOwnerLookupTag,
allowLazyDeclarationsCreation = true
).also {
check(it is Fir2IrLazySimpleFunction)
}
}
}
cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag)
return symbol
}
private inline fun <reified FC : FirCallableDeclaration, reified IS : IrSymbol> getCachedIrCallableSymbol(
@@ -1324,13 +1313,6 @@ internal var FirProperty.isStubPropertyForPureField: Boolean? by FirDeclarationD
@RequiresOptIn
annotation class LeakedDeclarationCaches
/**
* This annotation indicates that an annotated method can create a declaration in ad-hock way, so it should be used with caution
* In most cases, it's recommended to use method which return symbol or which forcefully creates a declaration
*/
@RequiresOptIn
annotation class GetOrCreateSensitiveAPI
/**
* This function is introduced as preparation to publishing unbound symbols in fir2ir
* There is a probability that it won't be non needed in future, but for now it allows
@@ -164,7 +164,6 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
val firDeclaration = findDeclarationByHash(firCandidates, signature.id) ?: return null
val parent = parentClass ?: declarationStorage.getIrExternalPackageFragment(packageFqName, firDeclaration.moduleData)
@OptIn(GetOrCreateSensitiveAPI::class)
return when (kind) {
SymbolKind.CLASS_SYMBOL -> {
classifierStorage.getOrCreateIrClass((firDeclaration as FirRegularClass).symbol)
@@ -173,8 +172,7 @@ class FirIrProvider(val components: Fir2IrComponents) : IrProvider {
firDeclaration as FirEnumEntry, parent as IrClass
)
SymbolKind.CONSTRUCTOR_SYMBOL -> {
val firConstructor = firDeclaration as FirConstructor
declarationStorage.getOrCreateIrConstructor(firConstructor, parent as IrClass)
shouldNotBeCalled()
}
SymbolKind.FUNCTION_SYMBOL -> {
shouldNotBeCalled()
@@ -463,19 +463,27 @@ class CallAndReferenceGenerator(
explicitReceiver = qualifiedAccess.explicitReceiver
)
when (symbol) {
is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, irType, symbol)
is IrConstructorSymbol -> {
require(firSymbol is FirConstructorSymbol)
val constructor = firSymbol.unwrapCallRepresentative().fir as FirConstructor
val totalTypeParametersCount = constructor.typeParameters.size
val constructorTypeParametersCount = constructor.typeParameters.count { it is FirTypeParameter }
IrConstructorCallImpl(
startOffset,
endOffset,
irType,
symbol,
typeArgumentsCount = totalTypeParametersCount,
valueArgumentsCount = firSymbol.valueParametersSize(),
constructorTypeArgumentsCount = constructorTypeParametersCount,
)
}
is IrSimpleFunctionSymbol -> {
require(firSymbol is FirCallableSymbol<*>) { "Illegal symbol: ${firSymbol!!::class}" }
val valueParametersNumber = when (firSymbol) {
is FirSyntheticPropertySymbol -> 0
is FirNamedFunctionSymbol -> firSymbol.valueParameterSymbols.size + firSymbol.resolvedContextReceivers.size
is FirFunctionSymbol<*> -> firSymbol.valueParameterSymbols.size
else -> error("Illegal symbol: ${firSymbol::class}")
}
IrCallImpl(
startOffset, endOffset, irType, symbol,
typeArgumentsCount = firSymbol.typeParameterSymbols.size,
valueArgumentsCount = valueParametersNumber,
valueArgumentsCount = firSymbol.valueParametersSize(),
origin = calleeReference.statementOrigin(),
superQualifierSymbol = dispatchReceiver?.superQualifierSymbol()
)
@@ -553,6 +561,16 @@ class CallAndReferenceGenerator(
}
}
private fun FirCallableSymbol<*>.valueParametersSize(): Int {
return when (this) {
is FirSyntheticPropertySymbol -> 0
is FirNamedFunctionSymbol -> fir.valueParameters.size + fir.contextReceivers.size
is FirConstructorSymbol -> fir.valueParameters.size + fir.contextReceivers.size
is FirFunctionSymbol<*> -> fir.valueParameters.size
else -> error("Illegal symbol: ${this::class}")
}
}
private fun convertToIrSetCallForDynamic(
variableAssignment: FirVariableAssignment,
explicitReceiverExpression: IrExpression?,
@@ -45,10 +45,7 @@ import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import kotlin.contracts.ExperimentalContracts
@@ -176,15 +173,15 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
irParent: IrClass,
symbol: IrConstructorSymbol,
predefinedOrigin: IrDeclarationOrigin? = null,
allowLazyDeclarationsCreation: Boolean
): IrConstructor = convertCatching(constructor) {
val origin = constructor.computeIrOrigin(predefinedOrigin, irParent.origin)
val isPrimary = constructor.isPrimary
if (irParent is Fir2IrLazyClass) {
val lazyConstructor = lazyDeclarationsGenerator.createIrLazyConstructor(constructor, symbol, origin, irParent) as Fir2IrLazyConstructor
// Add to cache before generating parameters to prevent an infinite loop when an annotation value parameter is annotated
// with the annotation itself.
@OptIn(LeakedDeclarationCaches::class)
declarationStorage.cacheIrConstructor(constructor, lazyConstructor)
if (!allowLazyDeclarationsCreation) {
error("Lazy constructors should be processed in Fir2IrDeclarationStorage")
}
val lazyConstructor = lazyDeclarationsGenerator.createIrLazyConstructor(constructor, symbol, origin, irParent)
lazyConstructor.prepareTypeParameters()
return lazyConstructor
}
@@ -206,10 +203,6 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
).apply {
metadata = FirMetadataSource.Function(constructor)
annotationGenerator.generate(this, constructor)
// Add to cache before generating parameters to prevent an infinite loop when an annotation value parameter is annotated
// with the annotation itself.
@OptIn(LeakedDeclarationCaches::class)
declarationStorage.cacheIrConstructor(constructor, this)
declarationStorage.withScope(symbol) {
setParent(irParent)
addDeclarationToParent(this, irParent)
@@ -63,7 +63,7 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir
symbol: IrConstructorSymbol,
declarationOrigin: IrDeclarationOrigin,
lazyParent: IrDeclarationParent,
): IrConstructor = fir.convertWithOffsets { startOffset, endOffset ->
): Fir2IrLazyConstructor = fir.convertWithOffsets { startOffset, endOffset ->
Fir2IrLazyConstructor(components, startOffset, endOffset, declarationOrigin, fir, symbol, lazyParent)
}
@@ -164,8 +164,9 @@ class Fir2IrLazyClass(
scope.processDeclaredConstructors {
val constructor = it.fir
if (shouldBuildStub(constructor)) {
@OptIn(GetOrCreateSensitiveAPI::class)
result += declarationStorage.getOrCreateIrConstructor(constructor, this, origin)
// Lazy declarations are created together with their symbol, so it's safe to take the owner here
@OptIn(UnsafeDuringIrConstructionAPI::class)
result += declarationStorage.getIrConstructorSymbol(constructor.symbol).owner
}
}