[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.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
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.symbols.impl.IrFieldSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
|
|
||||||
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
||||||
private var tempIndex = 0
|
private var tempIndex = 0
|
||||||
|
|
||||||
private fun getKPropertyImplConstructor(receiverTypes: List<IrType>,
|
private fun getKPropertyImpl(receiverTypes: List<IrType>,
|
||||||
returnType: IrType,
|
isLocal: Boolean,
|
||||||
isLocal: Boolean,
|
isMutable: Boolean): IrClass {
|
||||||
isMutable: Boolean) : Pair<IrConstructorSymbol, List<IrType>> {
|
|
||||||
|
|
||||||
val symbols = context.ir.symbols
|
val symbols = context.ir.symbols
|
||||||
|
|
||||||
@@ -64,41 +58,32 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val arguments = (receiverTypes + listOf(returnType))
|
return classSymbol.owner
|
||||||
|
|
||||||
return classSymbol.constructors.single() to arguments
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
// Somehow there is no reasonable common ancestor for IrProperty and IrLocalDelegatedProperty,
|
// Somehow there is no reasonable common ancestor for IrProperty and IrLocalDelegatedProperty,
|
||||||
// so index by IrDeclaration.
|
// 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
|
fun kPropertyField(value: IrExpressionBody, id:Int) =
|
||||||
|
IrFieldImpl(
|
||||||
val arrayItemGetter = arrayClass.functions.single { it.name == Name.identifier("get") }
|
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
|
||||||
|
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
|
||||||
val anyType = context.irBuiltIns.anyType
|
IrFieldSymbolImpl(),
|
||||||
val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType)
|
"KPROPERTY${id}".synthesizedName,
|
||||||
|
value.expression.type,
|
||||||
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
|
DescriptorVisibilities.PRIVATE,
|
||||||
|
isFinal = true,
|
||||||
val kPropertiesField =
|
isExternal = false,
|
||||||
IrFieldImpl(
|
isStatic = true,
|
||||||
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
|
).apply {
|
||||||
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
|
parent = irFile
|
||||||
IrFieldSymbolImpl(),
|
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.eagerInitialization.owner)
|
||||||
"KPROPERTIES".synthesizedName,
|
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.sharedImmutable.owner)
|
||||||
kPropertiesFieldType,
|
initializer = value
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
@@ -111,19 +96,19 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
irBuilder.run {
|
irBuilder.run {
|
||||||
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
||||||
return when (receiversCount) {
|
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}")
|
2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.symbol.owner.name}")
|
||||||
|
|
||||||
else -> { // Cache KProperties with no arguments.
|
else -> { // Cache KProperties with no arguments.
|
||||||
val field = kProperties.getOrPut(expression.symbol.owner) {
|
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 {
|
irGetField(null, field)
|
||||||
dispatchReceiver = irGetField(null, kPropertiesField)
|
|
||||||
putValueArgument(0, irInt(field.second))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,35 +127,28 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
else { // Cache KProperties with no arguments.
|
else { // Cache KProperties with no arguments.
|
||||||
// TODO: what about `receiversCount == 1` case?
|
// TODO: what about `receiversCount == 1` case?
|
||||||
val field = kProperties.getOrPut(expression.symbol.owner) {
|
val field = kProperties.getOrPut(expression.symbol.owner) {
|
||||||
createLocalKProperty(
|
kPropertyField(irExprBody(createLocalKProperty(
|
||||||
expression.symbol.owner.name.asString(),
|
expression.symbol.owner.name.asString(),
|
||||||
expression.getter.owner.returnType,
|
expression.getter.owner.returnType,
|
||||||
KTypeGenerator(this@PropertyDelegationLowering.context, irFile, expression),
|
KTypeGenerator(this@PropertyDelegationLowering.context, irFile, expression),
|
||||||
this
|
this
|
||||||
) to kProperties.size
|
)), kProperties.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
return irCall(arrayItemGetter).apply {
|
return irGetField(null, field)
|
||||||
dispatchReceiver = irGetField(null, kPropertiesField)
|
|
||||||
putValueArgument(0, irInt(field.second))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
irFile.declarations.addAll(0, kProperties.values)
|
||||||
if (kProperties.isNotEmpty()) {
|
irFile.declarations.addAll(generatedClasses)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKProperty(
|
private fun createKProperty(
|
||||||
expression: IrPropertyReference,
|
expression: IrPropertyReference,
|
||||||
irBuilder: IrBuilderWithScope
|
irBuilder: IrBuilderWithScope,
|
||||||
|
irFile: IrFile,
|
||||||
|
generatedClasses: MutableList<IrClass>
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
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 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 {
|
getter.extensionReceiverParameter.let {
|
||||||
if (it != null && expression.extensionReceiver == null)
|
if (it != null && expression.extensionReceiver == null)
|
||||||
receiverTypes.add(it.type)
|
receiverTypes.add(it.type)
|
||||||
@@ -204,10 +182,10 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
receiverTypes
|
receiverTypes
|
||||||
)
|
)
|
||||||
IrFunctionReferenceImpl(
|
IrFunctionReferenceImpl(
|
||||||
startOffset = startOffset,
|
startOffset = startOffset,
|
||||||
endOffset = endOffset,
|
endOffset = endOffset,
|
||||||
type = getterKFunctionType,
|
type = getterKFunctionType,
|
||||||
symbol = expression.getter!!,
|
symbol = expression.getter!!,
|
||||||
typeArgumentsCount = getter.typeParameters.size,
|
typeArgumentsCount = getter.typeParameters.size,
|
||||||
valueArgumentsCount = getter.valueParameters.size,
|
valueArgumentsCount = getter.valueParameters.size,
|
||||||
reflectionTarget = expression.getter!!
|
reflectionTarget = expression.getter!!
|
||||||
@@ -227,10 +205,10 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
receiverTypes + returnType
|
receiverTypes + returnType
|
||||||
)
|
)
|
||||||
IrFunctionReferenceImpl(
|
IrFunctionReferenceImpl(
|
||||||
startOffset = startOffset,
|
startOffset = startOffset,
|
||||||
endOffset = endOffset,
|
endOffset = endOffset,
|
||||||
type = setterKFunctionType,
|
type = setterKFunctionType,
|
||||||
symbol = expression.setter!!,
|
symbol = expression.setter!!,
|
||||||
typeArgumentsCount = setter.typeParameters.size,
|
typeArgumentsCount = setter.typeParameters.size,
|
||||||
valueArgumentsCount = setter.valueParameters.size,
|
valueArgumentsCount = setter.valueParameters.size,
|
||||||
reflectionTarget = expression.setter!!
|
reflectionTarget = expression.setter!!
|
||||||
@@ -243,15 +221,36 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
|
val clazz = getKPropertyImpl(
|
||||||
receiverTypes = receiverTypes,
|
receiverTypes = receiverTypes,
|
||||||
returnType = returnType,
|
isLocal = false,
|
||||||
isLocal = false,
|
isMutable = setterCallableReference != null)
|
||||||
isMutable = setterCallableReference != null)
|
|
||||||
val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
|
val name = irString(expression.symbol.owner.name.asString())
|
||||||
putValueArgument(0, irString(expression.symbol.owner.name.asString()))
|
|
||||||
if (getterCallableReference != null)
|
val initializer = if (dispatchReceiver == null && extensionReceiver == null) {
|
||||||
putValueArgument(1, getterCallableReference)
|
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)
|
if (setterCallableReference != null)
|
||||||
putValueArgument(2, setterCallableReference)
|
putValueArgument(2, setterCallableReference)
|
||||||
}
|
}
|
||||||
@@ -262,18 +261,16 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
private fun createLocalKProperty(propertyName: String,
|
private fun createLocalKProperty(propertyName: String,
|
||||||
propertyType: IrType,
|
propertyType: IrType,
|
||||||
kTypeGenerator: KTypeGenerator,
|
kTypeGenerator: KTypeGenerator,
|
||||||
irBuilder: IrBuilderWithScope): IrExpression {
|
irBuilder: IrBuilderWithScope): IrConstantValue {
|
||||||
irBuilder.run {
|
val symbols = context.ir.symbols
|
||||||
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
|
return irBuilder.run {
|
||||||
receiverTypes = emptyList(),
|
irConstantObject(
|
||||||
returnType = propertyType,
|
symbols.kLocalDelegatedPropertyImpl.owner,
|
||||||
isLocal = true,
|
mapOf(
|
||||||
isMutable = false)
|
"name" to irConstantPrimitive(irString(propertyName)),
|
||||||
val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
|
"returnType" to with(kTypeGenerator) { irKType(propertyType) }
|
||||||
putValueArgument(0, irString(propertyName))
|
)
|
||||||
putValueArgument(1, with(kTypeGenerator) { irKType(propertyType) })
|
)
|
||||||
}
|
|
||||||
return initializer
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user