Refactor AnnotationImplementationLowering

- Replaced UNDEFINED_OFFSET with SYNTHETIC_OFFSET, it's required by
  Native backend codegen
- Fixed missing overridden symbols
- Enforce adding fakeoverrides for members not overridden by backend
- Support more points for platform customisation
This commit is contained in:
Pavel Kunyavskiy
2021-09-13 10:32:37 +03:00
committed by Space
parent d9424fa092
commit 773c82ae48
5 changed files with 222 additions and 158 deletions
@@ -5,23 +5,28 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.lower.ANNOTATION_IMPLEMENTATION
import org.jetbrains.kotlin.backend.common.lower.AnnotationImplementationLowering
import org.jetbrains.kotlin.backend.common.lower.AnnotationImplementationTransformer
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -48,7 +53,7 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
return super.visitConstructorCall(expression)
}
override fun IrType.kClassToJClassIfNeeded(): IrType = when {
private fun IrType.kClassToJClassIfNeeded(): IrType = when {
this.isKClass() -> jvmContext.ir.symbols.javaLangClass.starProjectedType
this.isKClassArray() -> jvmContext.irBuiltIns.arrayClass.typeWith(
jvmContext.ir.symbols.javaLangClass.starProjectedType
@@ -71,20 +76,13 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
}
}
override fun generatedEquals(irBuilder: IrBlockBodyBuilder, type: IrType, arg1: IrExpression, arg2: IrExpression): IrExpression {
return if (type.isArray() || type.isPrimitiveArray()) {
val targetType = if (type.isPrimitiveArray()) type else jvmContext.ir.symbols.arrayOfAnyNType
val requiredSymbol = jvmContext.ir.symbols.arraysClass.owner.findDeclaration<IrFunction> {
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
}
requireNotNull(requiredSymbol) { "Can't find Arrays.equals method for type ${targetType.render()}" }
irBuilder.irCall(
requiredSymbol.symbol
).apply {
putValueArgument(0, arg1)
putValueArgument(1, arg2)
}
} else super.generatedEquals(irBuilder, type, arg1, arg2)
override fun getArrayContentEqualsSymbol(type: IrType): IrFunctionSymbol {
val targetType = if (type.isPrimitiveArray()) type else jvmContext.ir.symbols.arrayOfAnyNType
val requiredSymbol = jvmContext.ir.symbols.arraysClass.owner.findDeclaration<IrFunction> {
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
}
requireNotNull(requiredSymbol) { "Can't find Arrays.equals method for type ${targetType.render()}" }
return requiredSymbol.symbol
}
override fun implementPlatformSpecificParts(annotationClass: IrClass, implClass: IrClass) {
@@ -107,4 +105,97 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
}
}
}
override fun implementAnnotationPropertiesAndConstructor(
implClass: IrClass,
annotationClass: IrClass,
generatedConstructor: IrConstructor
) {
val ctorBody = context.irFactory.createBlockBody(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, listOf(
IrDelegatingConstructorCallImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.irBuiltIns.unitType, context.irBuiltIns.anyClass.constructors.single(),
typeArgumentsCount = 0, valueArgumentsCount = 0
)
)
)
generatedConstructor.body = ctorBody
annotationClass.getAnnotationProperties().forEach { property ->
val propType = property.getter!!.returnType
val propName = property.name
val field = context.irFactory.buildField {
startOffset = SYNTHETIC_OFFSET
endOffset = SYNTHETIC_OFFSET
name = propName
type = propType
origin = ANNOTATION_IMPLEMENTATION
isFinal = true
visibility = DescriptorVisibilities.PRIVATE
}.also { it.parent = implClass }
val parameter = generatedConstructor.addValueParameter(propName.asString(), propType)
// VALUE_FROM_PARAMETER
val originalParameter = ((property.backingField?.initializer?.expression as? IrGetValue)?.symbol?.owner as? IrValueParameter)
if (originalParameter?.defaultValue != null) {
parameter.defaultValue = originalParameter.defaultValue!!.deepCopyWithVariables().also { it.transformChildrenVoid() }
}
ctorBody.statements += IrSetFieldImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, field.symbol,
IrGetValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, implClass.thisReceiver!!.symbol),
IrGetValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, parameter.symbol),
context.irBuiltIns.unitType,
)
val prop = implClass.addProperty {
startOffset = SYNTHETIC_OFFSET
endOffset = SYNTHETIC_OFFSET
name = propName
isVar = false
origin = ANNOTATION_IMPLEMENTATION
}.apply {
field.correspondingPropertySymbol = this.symbol
backingField = field
parent = implClass
overriddenSymbols = listOf(property.symbol)
}
prop.addGetter {
startOffset = SYNTHETIC_OFFSET
endOffset = SYNTHETIC_OFFSET
name = propName // Annotation value getter should be named 'x', not 'getX'
returnType = propType.kClassToJClassIfNeeded() // On JVM, annotation store j.l.Class even if declared with KClass
origin = ANNOTATION_IMPLEMENTATION
visibility = DescriptorVisibilities.PUBLIC
modality = Modality.FINAL
}.apply {
correspondingPropertySymbol = prop.symbol
dispatchReceiverParameter = implClass.thisReceiver!!.copyTo(this)
body = context.createIrBuilder(symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
var value: IrExpression = irGetField(irGet(dispatchReceiverParameter!!), field)
if (propType.isKClass()) value = this.kClassExprToJClassIfNeeded(value)
+irReturn(value)
}
overriddenSymbols = listOf(property.getter!!.symbol)
}
}
}
override fun generateFunctionBodies(
annotationClass: IrClass,
implClass: IrClass,
eqFun: IrSimpleFunction,
hcFun: IrSimpleFunction,
toStringFun: IrSimpleFunction,
generator: AnnotationImplementationMemberGenerator
) {
val properties = annotationClass.getAnnotationProperties()
val implProperties = implClass.getAnnotationProperties()
generator.generateEqualsUsingGetters(eqFun, annotationClass.defaultType, properties)
generator.generateHashCodeMethod(hcFun, implProperties)
generator.generateToStringMethod(toStringFun, implProperties)
}
}