Find correct class owner for inlined local delegated properties

Note that call-site class has no metadata for inlined local delegated
properties. Thus, for an inlined local delegated property we should
obtain declaration-site class as owner - otherwise, the corresponding
`PropertyReference` will have an owner without property metadata.
This commit is contained in:
vladislav.grechko
2023-06-22 20:23:58 +02:00
parent d6d1ed6c35
commit a6e45f9b59
3 changed files with 22 additions and 10 deletions
@@ -94,10 +94,12 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
private val useOptimizedSuperClass =
context.state.generateOptimizedCallableReferenceSuperClasses
private val IrClass.isSynthetic
get() = metadata !is MetadataSource.File && metadata !is MetadataSource.Class && metadata !is MetadataSource.Script
private val IrMemberAccessExpression<*>.propertyContainer: IrDeclarationParent
get() = if (this is IrLocalDelegatedPropertyReference)
currentClassData?.localPropertyOwner(getter)
?: throw AssertionError("local property reference before declaration: ${render()}")
findClassOwner()
else
getter?.owner?.parent ?: field?.owner?.parent ?: error("Property without getter or field: ${dump()}")
@@ -106,6 +108,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
private val IrField.fakeGetterSignature: String
get() = "${JvmAbi.getterName(name.asString())}()${context.defaultMethodSignatureMapper.mapReturnType(this)}"
private val IrDeclaration.parentsWithSelf: Sequence<IrDeclaration>
get() = generateSequence(this) { it.parent as? IrDeclaration }
private fun IrLocalDelegatedPropertyReference.findClassOwner(): IrClass {
val originalBeforeInline = originalBeforeInline
if (originalBeforeInline != null) {
require(originalBeforeInline is IrLocalDelegatedPropertyReference) {
"Original for local delegated property ${render()} has another type: ${originalBeforeInline.render()}"
}
return originalBeforeInline.findClassOwner()
}
val containingClasses = symbol.owner.parentsWithSelf.filterIsInstance<IrClass>()
// Prefer to attach metadata to non-synthetic classes, similarly to how it's done in rememberLocalProperty.
return containingClasses.firstOrNull { !it.isSynthetic } ?: containingClasses.first()
}
private fun IrBuilderWithScope.computeSignatureString(expression: IrMemberAccessExpression<*>): IrExpression {
if (expression is IrLocalDelegatedPropertyReference) {
// Local delegated properties are stored as a plain list, and the runtime library extracts the index from this string:
@@ -213,19 +232,14 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
val localProperties = mutableListOf<IrLocalDelegatedPropertySymbol>()
val localPropertyIndices = mutableMapOf<IrSymbol, Int>()
val isSynthetic = irClass.metadata !is MetadataSource.File && irClass.metadata !is MetadataSource.Class &&
irClass.metadata !is MetadataSource.Script
fun localPropertyIndex(getter: IrSymbol): Int? =
localPropertyIndices[getter] ?: parent?.localPropertyIndex(getter)
fun localPropertyOwner(getter: IrSymbol): IrClass? =
if (getter in localPropertyIndices) irClass else parent?.localPropertyOwner(getter)
fun rememberLocalProperty(property: IrLocalDelegatedProperty) {
// Prefer to attach metadata to non-synthetic classes, because it won't be serialized otherwise;
// if not possible, though, putting it right here will at least allow non-reflective uses.
val metadataOwner = generateSequence(this) { it.parent }.find { !it.isSynthetic } ?: this
val metadataOwner = generateSequence(this) { it.parent }.find { !it.irClass.isSynthetic } ?: this
metadataOwner.localPropertyIndices[property.getter.symbol] = metadataOwner.localProperties.size
metadataOwner.localProperties.add(property.symbol)
}
@@ -1,6 +1,5 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_REFLECT
// FILE: 1.kt
package test
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_REFLECT
import kotlin.reflect.*