[FIR2IR] Manage function symbols in declaration storage instead of declaration generator

This is needed to be able to implement creation of unbound symbols
  for references of corresponding declarations (KT-62856)

There was an exception from FIR2IR that was fixed with this change,
  so fir2ir test expectDeclarationWithWeakIncompatibilities started to
  pass along with IrActualizer, which reported some new errors
This commit is contained in:
Dmitriy Novozhilov
2023-11-03 13:56:03 +02:00
committed by Space Team
parent 953f6ba6b6
commit 3c0f153de4
5 changed files with 90 additions and 100 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.classId
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
@@ -312,9 +313,14 @@ class Fir2IrDeclarationStorage(
isLocal: Boolean = false, isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrSimpleFunction { ): IrSimpleFunction {
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(function, fakeOverrideOwnerLookupTag)
}
val irFunction = callablesGenerator.createIrFunction( val irFunction = callablesGenerator.createIrFunction(
function, function,
irParent, irParent,
createFunctionSymbol(signature),
predefinedOrigin, predefinedOrigin,
isLocal = isLocal, isLocal = isLocal,
fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag
@@ -324,6 +330,13 @@ class Fir2IrDeclarationStorage(
return irFunction return irFunction
} }
internal fun createFunctionSymbol(signature: IdSignature?): IrSimpleFunctionSymbol {
return when {
signature != null -> symbolTable.referenceSimpleFunction(signature)
else -> IrSimpleFunctionSymbolImpl()
}
}
private fun cacheIrFunction(function: FirFunction, irFunction: IrSimpleFunction, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) { private fun cacheIrFunction(function: FirFunction, irFunction: IrSimpleFunction, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?) {
when { when {
irFunction.visibility == DescriptorVisibilities.LOCAL -> { irFunction.visibility == DescriptorVisibilities.LOCAL -> {
@@ -307,34 +307,32 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) : Fir2IrCompon
isOperator: Boolean = false, isOperator: Boolean = false,
): IrSimpleFunction { ): IrSimpleFunction {
val signature = if (klass.symbol.classId.isLocal) null else components.signatureComposer.composeSignature(syntheticCounterpart) val signature = if (klass.symbol.classId.isLocal) null else components.signatureComposer.composeSignature(syntheticCounterpart)
return components.callablesGenerator.declareIrSimpleFunction(signature) { symbol -> val symbol = components.declarationStorage.createFunctionSymbol(signature)
components.irFactory.createSimpleFunction( return components.irFactory.createSimpleFunction(
startOffset = UNDEFINED_OFFSET, startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET,
origin = origin, origin = origin,
name = name, name = name,
visibility = DescriptorVisibilities.PUBLIC, visibility = DescriptorVisibilities.PUBLIC,
isInline = false, isInline = false,
isExpect = false, isExpect = false,
returnType = returnType, returnType = returnType,
modality = Modality.OPEN, modality = Modality.OPEN,
symbol = symbol, symbol = symbol,
isTailrec = false, isTailrec = false,
isSuspend = false, isSuspend = false,
isOperator = isOperator, isOperator = isOperator,
isInfix = false, isInfix = false,
isExternal = false, isExternal = false,
isFakeOverride = false, isFakeOverride = false,
).apply { ).apply {
if (otherParameterNeeded) { if (otherParameterNeeded) {
val irValueParameter = createSyntheticIrParameter( val irValueParameter = createSyntheticIrParameter(
this, syntheticCounterpart.valueParameters.first().name, components.irBuiltIns.anyNType this, syntheticCounterpart.valueParameters.first().name, components.irBuiltIns.anyNType
) )
this.valueParameters = listOf(irValueParameter) this.valueParameters = listOf(irValueParameter)
}
metadata = FirMetadataSource.Function(syntheticCounterpart)
} }
}.apply { metadata = FirMetadataSource.Function(syntheticCounterpart)
setParent(irClass) setParent(irClass)
addDeclarationToParent(this, irClass) addDeclarationToParent(this, irClass)
dispatchReceiverParameter = generateDispatchReceiverParameter(this) dispatchReceiverParameter = generateDispatchReceiverParameter(this)
@@ -84,6 +84,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
fun createIrFunction( fun createIrFunction(
function: FirFunction, function: FirFunction,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
symbol: IrSimpleFunctionSymbol,
predefinedOrigin: IrDeclarationOrigin? = null, predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false, isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
@@ -109,26 +110,9 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
fakeOverrideOwnerLookupTag fakeOverrideOwnerLookupTag
) )
} }
val parentIsExternal = irParent.isExternalParent() if (irParent.isExternalParent()) {
// We don't generate signatures for local classes
// We attempt to avoid signature generation for non-local classes, with the following exceptions:
// - special mode (generateSignatures) oriented on special backend modes
// - lazy classes (they still use signatures)
// - primitive types (they can be from built-ins and don't have FIR counterpart)
// - overrides and fake overrides (sometimes we perform "receiver replacement" in FIR2IR breaking FIR->IR relation,
// or FIR counterpart can be just created on the fly)
val signature =
runUnless(
isLocal ||
!configuration.linkViaSignatures && !parentIsExternal &&
function.dispatchReceiverType?.isPrimitive != true && function.containerSource == null &&
updatedOrigin != IrDeclarationOrigin.FAKE_OVERRIDE && !function.isOverride
) {
signatureComposer.composeSignature(function, fakeOverrideOwnerLookupTag)
}
if (parentIsExternal && signature != null) {
// For private functions signature is null, fallback to non-lazy function // For private functions signature is null, fallback to non-lazy function
return lazyDeclarationsGenerator.createIrLazyFunction(function as FirSimpleFunction, signature, irParent!!, updatedOrigin) return lazyDeclarationsGenerator.createIrLazyFunction(function as FirSimpleFunction, symbol, irParent!!, updatedOrigin)
} }
val name = simpleFunction?.name val name = simpleFunction?.name
?: if (isLambda) SpecialNames.ANONYMOUS else SpecialNames.NO_NAME_PROVIDED ?: if (isLambda) SpecialNames.ANONYMOUS else SpecialNames.NO_NAME_PROVIDED
@@ -138,44 +122,42 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendOrKSuspendFunctionType(session) == true if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendOrKSuspendFunctionType(session) == true
else function.isSuspend else function.isSuspend
val created = function.convertWithOffsets { startOffset, endOffset -> val created = function.convertWithOffsets { startOffset, endOffset ->
declareIrSimpleFunction(signature) { symbol -> classifierStorage.preCacheTypeParameters(function, symbol)
classifierStorage.preCacheTypeParameters(function, symbol) irFactory.createSimpleFunction(
irFactory.createSimpleFunction( startOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else startOffset,
startOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else startOffset, endOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else endOffset,
endOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else endOffset, origin = updatedOrigin,
origin = updatedOrigin, name = name,
name = name, visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility),
visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility), isInline = simpleFunction?.isInline == true,
isInline = simpleFunction?.isInline == true, isExpect = simpleFunction?.isExpect == true,
isExpect = simpleFunction?.isExpect == true, returnType = function.returnTypeRef.toIrType(),
returnType = function.returnTypeRef.toIrType(), modality = simpleFunction?.modality ?: Modality.FINAL,
modality = simpleFunction?.modality ?: Modality.FINAL, symbol = symbol,
symbol = symbol, isTailrec = simpleFunction?.isTailRec == true,
isTailrec = simpleFunction?.isTailRec == true, isSuspend = isSuspend,
isSuspend = isSuspend, isOperator = simpleFunction?.isOperator == true,
isOperator = simpleFunction?.isOperator == true, isInfix = simpleFunction?.isInfix == true,
isInfix = simpleFunction?.isInfix == true, isExternal = simpleFunction?.isExternal == true,
isExternal = simpleFunction?.isExternal == true, containerSource = simpleFunction?.containerSource,
containerSource = simpleFunction?.containerSource, ).apply {
).apply { metadata = FirMetadataSource.Function(function)
metadata = FirMetadataSource.Function(function) declarationStorage.withScope(symbol) {
declarationStorage.withScope(symbol) { /*
/* * `isLocal = true` indicates that a function is local or member of a local class
* `isLocal = true` indicates that a function is local or member of a local class * containingClassLookupTag allows to distinguish those two cases
* containingClassLookupTag allows to distinguish those two cases */
*/ setParent(irParent)
setParent(irParent) if (!(isLocal && function.containingClassLookupTag() == null)) {
if (!(isLocal && function.containingClassLookupTag() == null)) { addDeclarationToParent(this, irParent)
addDeclarationToParent(this, irParent)
}
declareParameters(
function, irParent,
dispatchReceiverType = computeDispatchReceiverType(this, simpleFunction, irParent),
isStatic = simpleFunction?.isStatic == true,
forSetter = false,
)
convertAnnotationsForNonDeclaredMembers(function, origin)
} }
declareParameters(
function, irParent,
dispatchReceiverType = computeDispatchReceiverType(this, simpleFunction, irParent),
isStatic = simpleFunction?.isStatic == true,
forSetter = false,
)
convertAnnotationsForNonDeclaredMembers(function, origin)
} }
} }
} }
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.lazy.* import org.jetbrains.kotlin.fir.lazy.*
import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldPublicSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrPropertyPublicSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrPropertyPublicSymbolImpl
@@ -23,25 +24,21 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components { class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2IrComponents by components {
internal fun createIrLazyFunction( internal fun createIrLazyFunction(
fir: FirSimpleFunction, fir: FirSimpleFunction,
signature: IdSignature, symbol: IrSimpleFunctionSymbol,
lazyParent: IrDeclarationParent, lazyParent: IrDeclarationParent,
declarationOrigin: IrDeclarationOrigin declarationOrigin: IrDeclarationOrigin
): IrSimpleFunction { ): IrSimpleFunction {
val symbol = symbolTable.referenceSimpleFunction(signature)
val irFunction = fir.convertWithOffsets { startOffset, endOffset -> val irFunction = fir.convertWithOffsets { startOffset, endOffset ->
symbolTable.declareSimpleFunction(signature, { symbol }) { val firContainingClass = (lazyParent as? Fir2IrLazyClass)?.fir
val firContainingClass = (lazyParent as? Fir2IrLazyClass)?.fir val isFakeOverride = fir.isFakeOverride(firContainingClass)
val isFakeOverride = fir.isFakeOverride(firContainingClass) Fir2IrLazySimpleFunction(
Fir2IrLazySimpleFunction( components, startOffset, endOffset, declarationOrigin,
components, startOffset, endOffset, declarationOrigin, fir, firContainingClass, symbol, isFakeOverride
fir, firContainingClass, symbol, isFakeOverride ).apply {
).apply { this.parent = lazyParent
this.parent = lazyParent prepareTypeParameters()
}
} }
} }
// NB: this is needed to prevent recursions in case of self bounds
(irFunction as Fir2IrLazySimpleFunction).prepareTypeParameters()
return irFunction return irFunction
} }
@@ -2,14 +2,14 @@
// MODULE: m1-common // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
expect class Foo1 <!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo1<!>
expect class Foo2 <!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo2<!>
expect fun foo2(): Int expect fun foo2(): Int
expect val s: String <!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect val s: String<!>
expect open class Foo3 <!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect open class Foo3<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)