From 89414eb2146c58e6860d7734cf0e8a1d9af378cd Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Fri, 16 Jul 2021 14:38:24 +0300 Subject: [PATCH] [K/N] Transform some KProperties to ConstantValue --- .../backend/konan/lower/DelegationLowering.kt | 175 +++++++++--------- 1 file changed, 86 insertions(+), 89 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt index d23e32ab090..0f8a8051f06 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt @@ -16,26 +16,20 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference -import org.jetbrains.kotlin.ir.expressions.IrPropertyReference +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.Name internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { private var tempIndex = 0 - private fun getKPropertyImplConstructor(receiverTypes: List, - returnType: IrType, - isLocal: Boolean, - isMutable: Boolean) : Pair> { + private fun getKPropertyImpl(receiverTypes: List, + isLocal: Boolean, + isMutable: Boolean): IrClass { val symbols = context.ir.symbols @@ -64,41 +58,32 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } } - val arguments = (receiverTypes + listOf(returnType)) - - return classSymbol.constructors.single() to arguments + return classSymbol.owner } override fun lower(irFile: IrFile) { // Somehow there is no reasonable common ancestor for IrProperty and IrLocalDelegatedProperty, // so index by IrDeclaration. - val kProperties = mutableMapOf>() + val kProperties = mutableMapOf() + val generatedClasses = mutableListOf() - val arrayClass = context.ir.symbols.array.owner - - val arrayItemGetter = arrayClass.functions.single { it.name == Name.identifier("get") } - - val anyType = context.irBuiltIns.anyType - val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType) - - val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType) - - val kPropertiesField = - IrFieldImpl( - SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, - IrFieldSymbolImpl(), - "KPROPERTIES".synthesizedName, - kPropertiesFieldType, - DescriptorVisibilities.PRIVATE, - isFinal = true, - isExternal = false, - isStatic = true, - ).apply { - parent = irFile - annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.sharedImmutable.owner) - annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.eagerInitialization.owner) - } + fun kPropertyField(value: IrExpressionBody, id:Int) = + IrFieldImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, + IrFieldSymbolImpl(), + "KPROPERTY${id}".synthesizedName, + value.expression.type, + DescriptorVisibilities.PRIVATE, + isFinal = true, + isExternal = false, + isStatic = true, + ).apply { + parent = irFile + annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.eagerInitialization.owner) + annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.sharedImmutable.owner) + initializer = value + } irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { @@ -111,19 +96,19 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa irBuilder.run { val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null } return when (receiversCount) { - 1 -> createKProperty(expression, this) // Has receiver. + 1 -> createKProperty(expression, this, irFile, generatedClasses) // Has receiver. 2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.symbol.owner.name}") else -> { // Cache KProperties with no arguments. val field = kProperties.getOrPut(expression.symbol.owner) { - createKProperty(expression, this) to kProperties.size + kPropertyField( + irExprBody(createKProperty(expression, this, irFile, generatedClasses) as IrConstantValue), + kProperties.size + ) } - irCall(arrayItemGetter).apply { - dispatchReceiver = irGetField(null, kPropertiesField) - putValueArgument(0, irInt(field.second)) - } + irGetField(null, field) } } } @@ -142,35 +127,28 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa else { // Cache KProperties with no arguments. // TODO: what about `receiversCount == 1` case? val field = kProperties.getOrPut(expression.symbol.owner) { - createLocalKProperty( + kPropertyField(irExprBody(createLocalKProperty( expression.symbol.owner.name.asString(), expression.getter.owner.returnType, KTypeGenerator(this@PropertyDelegationLowering.context, irFile, expression), this - ) to kProperties.size + )), kProperties.size) } - return irCall(arrayItemGetter).apply { - dispatchReceiver = irGetField(null, kPropertiesField) - putValueArgument(0, irInt(field.second)) - } + return irGetField(null, field) } } } }) - - if (kProperties.isNotEmpty()) { - val initializers = kProperties.values.sortedBy { it.second }.map { it.first } - // TODO: replace with static initialization. - kPropertiesField.initializer = IrExpressionBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - context.createArrayOfExpression(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, kPropertyImplType, initializers)) - irFile.declarations.add(0, kPropertiesField) - } + irFile.declarations.addAll(0, kProperties.values) + irFile.declarations.addAll(generatedClasses) } private fun createKProperty( expression: IrPropertyReference, - irBuilder: IrBuilderWithScope + irBuilder: IrBuilderWithScope, + irFile: IrFile, + generatedClasses: MutableList ): IrExpression { val startOffset = expression.startOffset val endOffset = expression.endOffset @@ -190,7 +168,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } val returnType = expression.getter?.owner?.returnType ?: expression.field!!.owner.type - val getterCallableReference = expression.getter?.owner?.let { getter -> + val getterCallableReference = expression.getter!!.owner.let { getter -> getter.extensionReceiverParameter.let { if (it != null && expression.extensionReceiver == null) receiverTypes.add(it.type) @@ -204,10 +182,10 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa receiverTypes ) IrFunctionReferenceImpl( - startOffset = startOffset, - endOffset = endOffset, - type = getterKFunctionType, - symbol = expression.getter!!, + startOffset = startOffset, + endOffset = endOffset, + type = getterKFunctionType, + symbol = expression.getter!!, typeArgumentsCount = getter.typeParameters.size, valueArgumentsCount = getter.valueParameters.size, reflectionTarget = expression.getter!! @@ -227,10 +205,10 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa receiverTypes + returnType ) IrFunctionReferenceImpl( - startOffset = startOffset, - endOffset = endOffset, - type = setterKFunctionType, - symbol = expression.setter!!, + startOffset = startOffset, + endOffset = endOffset, + type = setterKFunctionType, + symbol = expression.setter!!, typeArgumentsCount = setter.typeParameters.size, valueArgumentsCount = setter.valueParameters.size, reflectionTarget = expression.setter!! @@ -243,15 +221,36 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } } - val (symbol, constructorTypeArguments) = getKPropertyImplConstructor( + val clazz = getKPropertyImpl( receiverTypes = receiverTypes, - returnType = returnType, - isLocal = false, - isMutable = setterCallableReference != null) - val initializer = irCall(symbol.owner, constructorTypeArguments).apply { - putValueArgument(0, irString(expression.symbol.owner.name.asString())) - if (getterCallableReference != null) - putValueArgument(1, getterCallableReference) + isLocal = false, + isMutable = setterCallableReference != null) + + val name = irString(expression.symbol.owner.name.asString()) + + val initializer = if (dispatchReceiver == null && extensionReceiver == null) { + fun IrFunctionReference.convert() : IrConstantValue { + val builder = FunctionReferenceLowering.FunctionReferenceBuilder( + irFile, + irFile, + this, + this@PropertyDelegationLowering.context, + irBuilder, + ) + val (newClass, newExpression) = builder.build() + generatedClasses.add(newClass) + return newExpression as IrConstantValue + } + return irConstantObject(clazz, @OptIn(ExperimentalStdlibApi::class) buildMap { + put("name", irConstantPrimitive(name)) + put("getter", getterCallableReference.convert()) + if (setterCallableReference != null) { + put("setter", setterCallableReference.convert()) + } + }) + } else irCall(clazz.constructors.single(), receiverTypes + listOf(returnType)).apply { + putValueArgument(0, name) + putValueArgument(1, getterCallableReference) if (setterCallableReference != null) putValueArgument(2, setterCallableReference) } @@ -262,18 +261,16 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa private fun createLocalKProperty(propertyName: String, propertyType: IrType, kTypeGenerator: KTypeGenerator, - irBuilder: IrBuilderWithScope): IrExpression { - irBuilder.run { - val (symbol, constructorTypeArguments) = getKPropertyImplConstructor( - receiverTypes = emptyList(), - returnType = propertyType, - isLocal = true, - isMutable = false) - val initializer = irCall(symbol.owner, constructorTypeArguments).apply { - putValueArgument(0, irString(propertyName)) - putValueArgument(1, with(kTypeGenerator) { irKType(propertyType) }) - } - return initializer + irBuilder: IrBuilderWithScope): IrConstantValue { + val symbols = context.ir.symbols + return irBuilder.run { + irConstantObject( + symbols.kLocalDelegatedPropertyImpl.owner, + mapOf( + "name" to irConstantPrimitive(irString(propertyName)), + "returnType" to with(kTypeGenerator) { irKType(propertyType) } + ) + ) } }