[K/N] Transform some KProperties to ConstantValue
This commit is contained in:
+86
-89
@@ -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<IrType>,
|
||||
returnType: IrType,
|
||||
isLocal: Boolean,
|
||||
isMutable: Boolean) : Pair<IrConstructorSymbol, List<IrType>> {
|
||||
private fun getKPropertyImpl(receiverTypes: List<IrType>,
|
||||
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<IrDeclaration, Pair<IrExpression, Int>>()
|
||||
val kProperties = mutableMapOf<IrDeclaration, IrField>()
|
||||
val generatedClasses = mutableListOf<IrClass>()
|
||||
|
||||
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<IrClass>
|
||||
): 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) }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user