[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.symbols.*
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.classId
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
@@ -312,9 +313,14 @@ class Fir2IrDeclarationStorage(
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
): IrSimpleFunction {
val signature = runIf(!isLocal && configuration.linkViaSignatures) {
signatureComposer.composeSignature(function, fakeOverrideOwnerLookupTag)
}
val irFunction = callablesGenerator.createIrFunction(
function,
irParent,
createFunctionSymbol(signature),
predefinedOrigin,
isLocal = isLocal,
fakeOverrideOwnerLookupTag = fakeOverrideOwnerLookupTag
@@ -324,6 +330,13 @@ class Fir2IrDeclarationStorage(
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?) {
when {
irFunction.visibility == DescriptorVisibilities.LOCAL -> {
@@ -307,34 +307,32 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) : Fir2IrCompon
isOperator: Boolean = false,
): IrSimpleFunction {
val signature = if (klass.symbol.classId.isLocal) null else components.signatureComposer.composeSignature(syntheticCounterpart)
return components.callablesGenerator.declareIrSimpleFunction(signature) { symbol ->
components.irFactory.createSimpleFunction(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
origin = origin,
name = name,
visibility = DescriptorVisibilities.PUBLIC,
isInline = false,
isExpect = false,
returnType = returnType,
modality = Modality.OPEN,
symbol = symbol,
isTailrec = false,
isSuspend = false,
isOperator = isOperator,
isInfix = false,
isExternal = false,
isFakeOverride = false,
).apply {
if (otherParameterNeeded) {
val irValueParameter = createSyntheticIrParameter(
this, syntheticCounterpart.valueParameters.first().name, components.irBuiltIns.anyNType
)
this.valueParameters = listOf(irValueParameter)
}
metadata = FirMetadataSource.Function(syntheticCounterpart)
val symbol = components.declarationStorage.createFunctionSymbol(signature)
return components.irFactory.createSimpleFunction(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
origin = origin,
name = name,
visibility = DescriptorVisibilities.PUBLIC,
isInline = false,
isExpect = false,
returnType = returnType,
modality = Modality.OPEN,
symbol = symbol,
isTailrec = false,
isSuspend = false,
isOperator = isOperator,
isInfix = false,
isExternal = false,
isFakeOverride = false,
).apply {
if (otherParameterNeeded) {
val irValueParameter = createSyntheticIrParameter(
this, syntheticCounterpart.valueParameters.first().name, components.irBuiltIns.anyNType
)
this.valueParameters = listOf(irValueParameter)
}
}.apply {
metadata = FirMetadataSource.Function(syntheticCounterpart)
setParent(irClass)
addDeclarationToParent(this, irClass)
dispatchReceiverParameter = generateDispatchReceiverParameter(this)
@@ -84,6 +84,7 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
fun createIrFunction(
function: FirFunction,
irParent: IrDeclarationParent?,
symbol: IrSimpleFunctionSymbol,
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
@@ -109,26 +110,9 @@ class Fir2IrCallableDeclarationsGenerator(val components: Fir2IrComponents) : Fi
fakeOverrideOwnerLookupTag
)
}
val parentIsExternal = 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) {
if (irParent.isExternalParent()) {
// 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
?: 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
else function.isSuspend
val created = function.convertWithOffsets { startOffset, endOffset ->
declareIrSimpleFunction(signature) { symbol ->
classifierStorage.preCacheTypeParameters(function, symbol)
irFactory.createSimpleFunction(
startOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else startOffset,
endOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else endOffset,
origin = updatedOrigin,
name = name,
visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility),
isInline = simpleFunction?.isInline == true,
isExpect = simpleFunction?.isExpect == true,
returnType = function.returnTypeRef.toIrType(),
modality = simpleFunction?.modality ?: Modality.FINAL,
symbol = symbol,
isTailrec = simpleFunction?.isTailRec == true,
isSuspend = isSuspend,
isOperator = simpleFunction?.isOperator == true,
isInfix = simpleFunction?.isInfix == true,
isExternal = simpleFunction?.isExternal == true,
containerSource = simpleFunction?.containerSource,
).apply {
metadata = FirMetadataSource.Function(function)
declarationStorage.withScope(symbol) {
/*
* `isLocal = true` indicates that a function is local or member of a local class
* containingClassLookupTag allows to distinguish those two cases
*/
setParent(irParent)
if (!(isLocal && function.containingClassLookupTag() == null)) {
addDeclarationToParent(this, irParent)
}
declareParameters(
function, irParent,
dispatchReceiverType = computeDispatchReceiverType(this, simpleFunction, irParent),
isStatic = simpleFunction?.isStatic == true,
forSetter = false,
)
convertAnnotationsForNonDeclaredMembers(function, origin)
classifierStorage.preCacheTypeParameters(function, symbol)
irFactory.createSimpleFunction(
startOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else startOffset,
endOffset = if (updatedOrigin == IrDeclarationOrigin.DELEGATED_MEMBER) SYNTHETIC_OFFSET else endOffset,
origin = updatedOrigin,
name = name,
visibility = components.visibilityConverter.convertToDescriptorVisibility(visibility),
isInline = simpleFunction?.isInline == true,
isExpect = simpleFunction?.isExpect == true,
returnType = function.returnTypeRef.toIrType(),
modality = simpleFunction?.modality ?: Modality.FINAL,
symbol = symbol,
isTailrec = simpleFunction?.isTailRec == true,
isSuspend = isSuspend,
isOperator = simpleFunction?.isOperator == true,
isInfix = simpleFunction?.isInfix == true,
isExternal = simpleFunction?.isExternal == true,
containerSource = simpleFunction?.containerSource,
).apply {
metadata = FirMetadataSource.Function(function)
declarationStorage.withScope(symbol) {
/*
* `isLocal = true` indicates that a function is local or member of a local class
* containingClassLookupTag allows to distinguish those two cases
*/
setParent(irParent)
if (!(isLocal && function.containingClassLookupTag() == null)) {
addDeclarationToParent(this, irParent)
}
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.resolve.providers.firProvider
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.IrFieldPublicSymbolImpl
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 {
internal fun createIrLazyFunction(
fir: FirSimpleFunction,
signature: IdSignature,
symbol: IrSimpleFunctionSymbol,
lazyParent: IrDeclarationParent,
declarationOrigin: IrDeclarationOrigin
): IrSimpleFunction {
val symbol = symbolTable.referenceSimpleFunction(signature)
val irFunction = fir.convertWithOffsets { startOffset, endOffset ->
symbolTable.declareSimpleFunction(signature, { symbol }) {
val firContainingClass = (lazyParent as? Fir2IrLazyClass)?.fir
val isFakeOverride = fir.isFakeOverride(firContainingClass)
Fir2IrLazySimpleFunction(
components, startOffset, endOffset, declarationOrigin,
fir, firContainingClass, symbol, isFakeOverride
).apply {
this.parent = lazyParent
}
val firContainingClass = (lazyParent as? Fir2IrLazyClass)?.fir
val isFakeOverride = fir.isFakeOverride(firContainingClass)
Fir2IrLazySimpleFunction(
components, startOffset, endOffset, declarationOrigin,
fir, firContainingClass, symbol, isFakeOverride
).apply {
this.parent = lazyParent
prepareTypeParameters()
}
}
// NB: this is needed to prevent recursions in case of self bounds
(irFunction as Fir2IrLazySimpleFunction).prepareTypeParameters()
return irFunction
}
@@ -2,14 +2,14 @@
// MODULE: m1-common
// FILE: common.kt
expect class Foo1
expect class Foo2
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo1<!>
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo2<!>
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)