FIR2IR: bind fake override calls via symbol table

This commit is contained in:
Mikhail Glukhikh
2021-10-26 13:32:08 +03:00
committed by teamcity
parent d4cdf874be
commit 5a44fda42c
6 changed files with 64 additions and 20 deletions
@@ -405,17 +405,32 @@ class Fir2IrDeclarationStorage(
if (function is FirSimpleFunction) getCachedIrFunction(function) if (function is FirSimpleFunction) getCachedIrFunction(function)
else localStorage.getLocalFunction(function) else localStorage.getLocalFunction(function)
fun getCachedIrFunction(function: FirSimpleFunction): IrSimpleFunction? {
return if (function.visibility == Visibilities.Local) {
localStorage.getLocalFunction(function)
} else {
functionCache[function]
}
}
fun getCachedIrFunction( fun getCachedIrFunction(
function: FirSimpleFunction, function: FirSimpleFunction,
signatureCalculator: (FirSimpleFunction) -> IdSignature? = { null } dispatchReceiverLookupTag: ConeClassLikeLookupTag?,
signatureCalculator: (FirSimpleFunction) -> IdSignature?
): IrSimpleFunction? { ): IrSimpleFunction? {
return if (function.visibility == Visibilities.Local) { return if (function.visibility == Visibilities.Local) {
localStorage.getLocalFunction(function) localStorage.getLocalFunction(function)
} else { } else {
functionCache[function] ?: signatureCalculator(function)?.let { signature -> val isFakeOverride = dispatchReceiverLookupTag != null &&
dispatchReceiverLookupTag !is ConeClassLookupTagWithFixedSymbol &&
dispatchReceiverLookupTag != function.containingClass()
val cached = if (isFakeOverride) null else functionCache[function]
cached ?: signatureCalculator(function)?.let { signature ->
symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol -> symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol ->
val irFunction = irFunctionSymbol.owner val irFunction = irFunctionSymbol.owner
functionCache[function] = irFunction if (!isFakeOverride) {
functionCache[function] = irFunction
}
irFunction irFunction
} }
} }
@@ -874,14 +889,23 @@ class Fir2IrDeclarationStorage(
} }
} }
fun getCachedIrProperty(property: FirProperty): IrProperty? = propertyCache[property]
fun getCachedIrProperty( fun getCachedIrProperty(
property: FirProperty, property: FirProperty,
signatureCalculator: (FirProperty) -> IdSignature? = { null } dispatchReceiverLookupTag: ConeClassLikeLookupTag?,
signatureCalculator: (FirProperty) -> IdSignature?
): IrProperty? { ): IrProperty? {
return propertyCache[property] ?: signatureCalculator(property)?.let { signature -> val isFakeOverride = dispatchReceiverLookupTag != null &&
dispatchReceiverLookupTag !is ConeClassLookupTagWithFixedSymbol &&
dispatchReceiverLookupTag != property.containingClass()
val cached = if (isFakeOverride) null else propertyCache[property]
return cached ?: signatureCalculator(property)?.let { signature ->
symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol -> symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol ->
val irProperty = irPropertySymbol.owner val irProperty = irPropertySymbol.owner
propertyCache[property] = irProperty if (!isFakeOverride) {
propertyCache[property] = irProperty
}
irProperty irProperty
} }
} }
@@ -1075,7 +1099,8 @@ class Fir2IrDeclarationStorage(
val fir = firConstructorSymbol.fir val fir = firConstructorSymbol.fir
return getIrCallableSymbol( return getIrCallableSymbol(
firConstructorSymbol, firConstructorSymbol,
getCachedIrDeclaration = ::getCachedIrConstructor, dispatchReceiverLookupTag = null,
getCachedIrDeclaration = { constructor: FirConstructor, _, calculator -> getCachedIrConstructor(constructor, calculator) },
createIrDeclaration = { parent, origin -> createIrConstructor(fir, parent as IrClass, predefinedOrigin = origin) }, createIrDeclaration = { parent, origin -> createIrConstructor(fir, parent as IrClass, predefinedOrigin = origin) },
createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> createIrLazyDeclaration = { signature, lazyParent, declarationOrigin ->
val symbol = Fir2IrConstructorSymbol(signature) val symbol = Fir2IrConstructorSymbol(signature)
@@ -1109,8 +1134,13 @@ class Fir2IrDeclarationStorage(
createIrFunction(fir, irParent, predefinedOrigin = declarationOrigin).symbol createIrFunction(fir, irParent, predefinedOrigin = declarationOrigin).symbol
} }
is FirSimpleFunction -> { is FirSimpleFunction -> {
val unmatchedReceiver = dispatchReceiverLookupTag != firFunctionSymbol.containingClass()
if (unmatchedReceiver) {
generateLazyFakeOverrides(fir.name, dispatchReceiverLookupTag)
}
val originalSymbol = getIrCallableSymbol( val originalSymbol = getIrCallableSymbol(
firFunctionSymbol, firFunctionSymbol,
dispatchReceiverLookupTag,
getCachedIrDeclaration = ::getCachedIrFunction, getCachedIrDeclaration = ::getCachedIrFunction,
createIrDeclaration = { parent, origin -> createIrFunction(fir, parent, predefinedOrigin = origin) }, createIrDeclaration = { parent, origin -> createIrFunction(fir, parent, predefinedOrigin = origin) },
createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> createIrLazyDeclaration = { signature, lazyParent, declarationOrigin ->
@@ -1135,14 +1165,14 @@ class Fir2IrDeclarationStorage(
irFunction irFunction
} }
) as IrFunctionSymbol ) as IrFunctionSymbol
if (dispatchReceiverLookupTag != null && dispatchReceiverLookupTag != firFunctionSymbol.containingClass()) { if (dispatchReceiverLookupTag is ConeClassLookupTagWithFixedSymbol && unmatchedReceiver) {
val dispatchReceiverIrClass = val dispatchReceiverIrClass =
classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner
dispatchReceiverIrClass.declarations.find { dispatchReceiverIrClass.declarations.find {
it is IrSimpleFunction && it.isFakeOverride && it.name == fir.name && it is IrSimpleFunction && it.isFakeOverride && it.name == fir.name &&
it.overrides(originalSymbol.owner as IrSimpleFunction) it.overrides(originalSymbol.owner as IrSimpleFunction)
}?.symbol as? IrFunctionSymbol }?.symbol as? IrFunctionSymbol
?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late) ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late for local classes)
} else { } else {
originalSymbol originalSymbol
} }
@@ -1162,8 +1192,13 @@ class Fir2IrDeclarationStorage(
if (fir.isLocal) { if (fir.isLocal) {
return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir) return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir)
} }
val unmatchedReceiver = dispatchReceiverLookupTag != firPropertySymbol.containingClass()
if (unmatchedReceiver) {
generateLazyFakeOverrides(fir.name, dispatchReceiverLookupTag)
}
val originalSymbol = getIrCallableSymbol( val originalSymbol = getIrCallableSymbol(
firPropertySymbol, firPropertySymbol,
dispatchReceiverLookupTag,
getCachedIrDeclaration = ::getCachedIrProperty, getCachedIrDeclaration = ::getCachedIrProperty,
createIrDeclaration = { parent, origin -> createIrProperty(fir, parent, predefinedOrigin = origin) }, createIrDeclaration = { parent, origin -> createIrProperty(fir, parent, predefinedOrigin = origin) },
createIrLazyDeclaration = { signature, lazyParent, declarationOrigin -> createIrLazyDeclaration = { signature, lazyParent, declarationOrigin ->
@@ -1185,33 +1220,46 @@ class Fir2IrDeclarationStorage(
return symbol return symbol
} }
) )
return if (dispatchReceiverLookupTag != null && dispatchReceiverLookupTag != firPropertySymbol.containingClass()) { return if (dispatchReceiverLookupTag is ConeClassLookupTagWithFixedSymbol &&
dispatchReceiverLookupTag != firPropertySymbol.containingClass()
) {
val dispatchReceiverIrClass = val dispatchReceiverIrClass =
classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner classifierStorage.getIrClassSymbol(dispatchReceiverLookupTag.toSymbol(session) as FirClassSymbol).owner
dispatchReceiverIrClass.declarations.find { dispatchReceiverIrClass.declarations.find {
it is IrProperty && it.isFakeOverride && it.name == fir.name && it.overrides(originalSymbol.owner as IrProperty) it is IrProperty && it.isFakeOverride && it.name == fir.name && it.overrides(originalSymbol.owner as IrProperty)
}?.symbol as? IrPropertySymbol }?.symbol as? IrPropertySymbol
?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late) ?: originalSymbol // Fallback (normally we should not be here, but f/o are bound too late for local classes)
} else { } else {
originalSymbol originalSymbol
} }
} }
private fun generateLazyFakeOverrides(name: Name, dispatchReceiverLookupTag: ConeClassLikeLookupTag?) {
val firClassSymbol = dispatchReceiverLookupTag?.toSymbol(session) as? FirClassSymbol
if (firClassSymbol != null) {
val irClass = classifierStorage.getIrClassSymbol(firClassSymbol).owner
if (irClass is Fir2IrLazyClass) {
irClass.getFakeOverridesByName(name)
}
}
}
private inline fun < private inline fun <
reified FS : FirCallableSymbol<*>, reified FS : FirCallableSymbol<*>,
reified F : FirCallableDeclaration, reified F : FirCallableDeclaration,
I : IrSymbolOwner, I : IrSymbolOwner,
> getIrCallableSymbol( > getIrCallableSymbol(
firSymbol: FS, firSymbol: FS,
getCachedIrDeclaration: (F, (F) -> IdSignature?) -> I?, dispatchReceiverLookupTag: ConeClassLikeLookupTag?,
getCachedIrDeclaration: (F, ConeClassLikeLookupTag?, (F) -> IdSignature?) -> I?,
createIrDeclaration: (IrDeclarationParent?, IrDeclarationOrigin) -> I, createIrDeclaration: (IrDeclarationParent?, IrDeclarationOrigin) -> I,
createIrLazyDeclaration: (IdSignature, Fir2IrLazyClass, IrDeclarationOrigin) -> I, createIrLazyDeclaration: (IdSignature, Fir2IrLazyClass, IrDeclarationOrigin) -> I,
): IrSymbol { ): IrSymbol {
val fir = firSymbol.fir as F val fir = firSymbol.fir as F
val irParent by lazy { findIrParent(fir) } val irParent by lazy { findIrParent(fir) }
val signature by lazy { signatureComposer.composeSignature(fir) } val signature by lazy { signatureComposer.composeSignature(fir, dispatchReceiverLookupTag) }
synchronized(symbolTable.lock) { synchronized(symbolTable.lock) {
getCachedIrDeclaration(fir) { getCachedIrDeclaration(fir, dispatchReceiverLookupTag) {
// Parent calculation provokes declaration calculation for some members from IrBuiltIns // Parent calculation provokes declaration calculation for some members from IrBuiltIns
@Suppress("UNUSED_EXPRESSION") irParent @Suppress("UNUSED_EXPRESSION") irParent
signature signature
@@ -184,7 +184,7 @@ class FakeOverrideGenerator(
irClass: IrClass, irClass: IrClass,
isLocal: Boolean, isLocal: Boolean,
originalSymbol: FirCallableSymbol<*>, originalSymbol: FirCallableSymbol<*>,
cachedIrDeclaration: (D, (D) -> IdSignature?) -> I?, cachedIrDeclaration: (D, ConeClassLikeLookupTag?, (D) -> IdSignature?) -> I?,
createIrDeclaration: (D, irParent: IrClass, thisReceiverOwner: IrClass?, origin: IrDeclarationOrigin, isLocal: Boolean) -> I, createIrDeclaration: (D, irParent: IrClass, thisReceiverOwner: IrClass?, origin: IrDeclarationOrigin, isLocal: Boolean) -> I,
createFakeOverrideSymbol: (D, S) -> S, createFakeOverrideSymbol: (D, S) -> S,
baseSymbols: MutableMap<I, List<S>>, baseSymbols: MutableMap<I, List<S>>,
@@ -227,7 +227,7 @@ class FakeOverrideGenerator(
return return
} }
} }
val irDeclaration = cachedIrDeclaration(fakeOverrideFirDeclaration) { val irDeclaration = cachedIrDeclaration(fakeOverrideFirDeclaration, null) {
// Sometimes we can have clashing here when FIR substitution/intersection override // Sometimes we can have clashing here when FIR substitution/intersection override
// have the same signature. // have the same signature.
// Now we avoid this problem by signature caching, // Now we avoid this problem by signature caching,
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: Z.kt // FILE: Z.kt
inline class Z(val x: Int) inline class Z(val x: Int)
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: Z.kt // FILE: Z.kt
inline class Z(val x: Int) inline class Z(val x: Int)
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: Z.kt // FILE: Z.kt
inline class Z(val x: Int) inline class Z(val x: Int)
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
// Completely incorrect bytecode - see `box/inlineClasses/toStringOfUnboxedNullable.kt` // Completely incorrect bytecode - see `box/inlineClasses/toStringOfUnboxedNullable.kt`
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM