[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:
Kristoffer Andersen
2020-01-29 16:22:23 +01:00
committed by Dmitry Petrov
parent d4170bca6e
commit 61e6d346aa
2 changed files with 19 additions and 10 deletions
@@ -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