[JVM IR] Interface Delegation by Property should use existing field
When a property backed by a final field is the delegate for interface implementation by delegation, the backend should reuse the backing field rather than introduce a new, extraneous `$$delegate_n` field.
This commit is contained in:
committed by
Dmitry Petrov
parent
d4170bca6e
commit
61e6d346aa
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -25,6 +26,8 @@ import org.jetbrains.kotlin.ir.expressions.mapValueParameters
|
||||
import org.jetbrains.kotlin.ir.expressions.putTypeArguments
|
||||
import org.jetbrains.kotlin.ir.expressions.typeParametersCount
|
||||
import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides
|
||||
import org.jetbrains.kotlin.ir.util.fields
|
||||
import org.jetbrains.kotlin.ir.util.properties
|
||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||
@@ -176,14 +179,21 @@ class ClassGenerator(
|
||||
val superClass = superTypeConstructorDescriptor as? ClassDescriptor
|
||||
?: throw AssertionError("Unexpected supertype constructor for delegation: $superTypeConstructorDescriptor")
|
||||
|
||||
val delegateDescriptor = IrImplementingDelegateDescriptorImpl(irClass.descriptor, delegateType, superType, delegateNumber)
|
||||
val irDelegateField = context.symbolTable.declareField(
|
||||
ktDelegateExpression.startOffsetSkippingComments, ktDelegateExpression.endOffset,
|
||||
IrDeclarationOrigin.DELEGATE,
|
||||
delegateDescriptor, delegateDescriptor.type.toIrType(),
|
||||
createBodyGenerator(irClass.symbol).generateExpressionBody(ktDelegateExpression)
|
||||
)
|
||||
irClass.addMember(irDelegateField)
|
||||
val propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(ktDelegateExpression, irClass.descriptor, context.bindingContext)
|
||||
|
||||
val irDelegateField: IrField = if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, context.bindingContext)) {
|
||||
irClass.properties.first { it.descriptor == propertyDescriptor }.backingField!!
|
||||
} else {
|
||||
val delegateDescriptor = IrImplementingDelegateDescriptorImpl(irClass.descriptor, delegateType, superType, delegateNumber)
|
||||
context.symbolTable.declareField(
|
||||
ktDelegateExpression.startOffsetSkippingComments, ktDelegateExpression.endOffset,
|
||||
IrDeclarationOrigin.DELEGATE,
|
||||
delegateDescriptor, delegateDescriptor.type.toIrType(),
|
||||
createBodyGenerator(irClass.symbol).generateExpressionBody(ktDelegateExpression)
|
||||
).apply {
|
||||
irClass.addMember(this)
|
||||
}
|
||||
}
|
||||
|
||||
val delegatesMap = DelegationResolver.getDelegates(irClass.descriptor, superClass, delegateType)
|
||||
val delegatedMembers = delegatesMap.keys.toList().sortedByRenderer()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_RUNTIME
|
||||
@@ -37,7 +36,7 @@ fun box(): String {
|
||||
|
||||
try {
|
||||
Test2::class.java.getDeclaredField("\$\$delegate_0")
|
||||
return "\$\$delegate_0 field generated for class Test but should not"
|
||||
return "\$\$delegate_0 field generated for class Test2 but should not"
|
||||
}
|
||||
catch (e: NoSuchFieldException) {
|
||||
// ok
|
||||
|
||||
Reference in New Issue
Block a user