[FIR2IR] Don't manually create IR for IntrinsicConstEvaluation if not needed

There is no need to create IR class for `@IntrinsicConstEvaluation` manually
  if it is present in sources

^KT-65415 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-03-07 15:03:16 +02:00
committed by Space Team
parent 7a383373b0
commit 555cf56d6d
4 changed files with 67 additions and 31 deletions
@@ -513,7 +513,7 @@ class Fir2IrDeclarationStorage(
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
): IrConstructor {
val symbol = getIrConstructorSymbol(constructor.symbol, isLocal)
val symbol = getIrConstructorSymbol(constructor.symbol, potentiallyExternal = !isLocal)
return callablesGenerator.createIrConstructor(
constructor,
irParent(),
@@ -527,13 +527,13 @@ class Fir2IrDeclarationStorage(
constructorCache[constructor] = irConstructorSymbol
}
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol, isLocal: Boolean = false): IrConstructorSymbol {
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol, potentiallyExternal: Boolean = true): 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 symbol = IrConstructorSymbolImpl()
if (!isLocal) {
if (potentiallyExternal) {
val irParent = findIrParent(constructor, fakeOverrideOwnerLookupTag = null)
val isIntrinsicConstEvaluation =
constructor.returnTypeRef.coneType.classId == StandardClassIds.Annotations.IntrinsicConstEvaluation
@@ -51,7 +51,7 @@ class Fir2IrTypeConverter(
StandardClassIds.Double to irBuiltIns.doubleClass,
StandardClassIds.Char to irBuiltIns.charClass,
StandardClassIds.Array to irBuiltIns.arrayClass,
StandardClassIds.Annotations.IntrinsicConstEvaluation to irBuiltIns.intrinsicConst
StandardClassIds.Annotations.IntrinsicConstEvaluation to irBuiltIns.intrinsicConstSymbol
)
}
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.constructors
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
@@ -125,40 +127,74 @@ class IrBuiltInsOverFir(
override val stringClass: IrClassSymbol by lazy { loadClass(StandardClassIds.String) }
override val stringType: IrType get() = stringClass.defaultTypeWithoutArguments
internal val intrinsicConst by lazy {
/*
* Old versions of stdlib may not contain @IntrinsicConstEvaluation (AV < 1.7), so in this case we should create annotation class manually
*
* Ideally, we should try to load it from FIR at first, but the thing is that this annotation is used for some generated builtin functions
* (see init section below), so if Fir2IrLazyClass for this annotation is created, it will call for `components.fakeOverrideGenerator`,
* which is not initialized by this moment
* As a possible way to fix it we can move `init` section of builtins into the separate function for late initialization and call
* for it after Fir2IrComponentsStorage is fully initialized
*/
val irClass = createIntrinsicConstEvaluationClass()
private class IntrinsicConstAnnotation(val classSymbol: IrClassSymbol, val annotationCall: IrConstructorCall)
private val intrinsicConst: IntrinsicConstAnnotation by lazy {
val firClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(
StandardClassIds.Annotations.IntrinsicConstEvaluation
) as FirRegularClassSymbol?
if (firClassSymbol != null) {
/*
* If @IntrinsicConstEvaluation is present in dependencies, we should manually cache relation between FIR and IR class
* Without it classifier storage may create another IR class for @IntrinsicConstEvaluation, if it will be referenced
* somewhere in the code
*/
@OptIn(LeakedDeclarationCaches::class)
components.classifierStorage.cacheIrClass(firClassSymbol.fir, irClass)
val (classSymbol, constructorSymbol) = when {
firClassSymbol?.origin == FirDeclarationOrigin.Source -> {
/**
* If @IntrinsicConstEvaluation is present in sources, then we are compiling stdlib and there is no need to create IrClass
* for it manually, as we will create it from the source FIR class
*/
val irClassSymbol = components.classifierStorage.getIrClassSymbol(firClassSymbol)
val firConstructor = firClassSymbol.fir.constructors(session).single()
val irConstructorSymbol = components.declarationStorage.getIrConstructorSymbol(firConstructor, potentiallyExternal = false)
irClassSymbol to irConstructorSymbol
}
else -> {
/*
* Old versions of stdlib may not contain @IntrinsicConstEvaluation (AV < 1.7), so in this case we should create annotation class manually
*
* Ideally, we should try to load it from FIR at first, but the thing is that this annotation is used for some generated builtin functions
* (see init section below), so if Fir2IrLazyClass for this annotation is created, it will call for `components.fakeOverrideGenerator`,
* which is not initialized by this moment
* As a possible way to fix it we can move `init` section of builtins into the separate function for late initialization and call
* for it after Fir2IrComponentsStorage is fully initialized
*/
val irClass = createIntrinsicConstEvaluationClass()
if (firClassSymbol != null) {
/*
* If @IntrinsicConstEvaluation is present in dependencies, we should manually cache relation between FIR and IR class
* Without it classifier storage may create another IR class for @IntrinsicConstEvaluation, if it will be referenced
* somewhere in the code
*/
@OptIn(LeakedDeclarationCaches::class)
components.classifierStorage.cacheIrClass(firClassSymbol.fir, irClass)
}
// class for intrinsicConst is created manually and it definitely is not a lazy class
@OptIn(UnsafeDuringIrConstructionAPI::class)
val constructor = irClass.constructors.single()
irClass.symbol to constructor.symbol
}
}
irClass.symbol
val annotationCall = IrConstructorCallImpl(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
type = IrSimpleTypeImpl(
classifier = classSymbol,
nullability = SimpleTypeNullability.DEFINITELY_NOT_NULL,
arguments = emptyList(),
annotations = emptyList()
),
constructorSymbol,
typeArgumentsCount = 0,
constructorTypeArgumentsCount = 0,
valueArgumentsCount = 0,
)
IntrinsicConstAnnotation(classSymbol, annotationCall)
}
private val intrinsicConstAnnotation: IrConstructorCall by lazy {
// class for intrinsicConst is created manually and it definitely is not a lazy class
@OptIn(UnsafeDuringIrConstructionAPI::class)
val constructor = intrinsicConst.constructors.single()
IrConstructorCallImpl.Companion.fromSymbolOwner(intrinsicConst.defaultType, constructor)
}
internal val intrinsicConstSymbol: IrClassSymbol
get() = intrinsicConst.classSymbol
private val intrinsicConstAnnotation: IrConstructorCall
get() = intrinsicConst.annotationCall
override val iteratorClass: IrClassSymbol by lazy { loadClass(StandardClassIds.Iterator) }
override val arrayClass: IrClassSymbol by lazy { loadClass(StandardClassIds.Array) }
@@ -1,5 +1,5 @@
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6, WASM, NATIVE
// IGNORE_BACKEND_K2: ANY
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, WASM, NATIVE
// non-jvm backends are ignored because of KT-66432
// ISSUE: KT-65415, KT-66432