Implemented delegated properties.
This commit is contained in:
+4
-2
@@ -4,7 +4,6 @@ import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.konan.lower.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
|
||||
internal class KonanLower(val context: Context) {
|
||||
|
||||
@@ -39,6 +38,10 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_DELEGATION) {
|
||||
ClassDelegationLowering(context).runOnFilePostfix(irFile)
|
||||
PropertyDelegationLowering(context).lower(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) {
|
||||
TypeOperatorLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
@@ -58,7 +61,6 @@ internal class KonanLower(val context: Context) {
|
||||
VarargInjectionLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
|
||||
DelegationLowering(context).runOnFilePostfix(irFile)
|
||||
BridgesBuilding(context).runOnFilePostfix(irFile)
|
||||
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ enum class KonanPhase(val description: String,
|
||||
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
|
||||
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering"),
|
||||
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
|
||||
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
|
||||
/* ... */ BITCODE("LLVM BitCode Generation"),
|
||||
/* ... ... */ RTTI("RTTI Generation"),
|
||||
/* ... ... */ CODEGEN("Code Generation"),
|
||||
|
||||
+5
-2
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -1226,7 +1227,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
context.log("evaluateGetField : ${ir2string(value)}")
|
||||
if (value.descriptor.dispatchReceiverParameter != null
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
|
||||
|| value.descriptor is IrImplementingDelegateDescriptorImpl
|
||||
|| (value.descriptor is IrPropertyDelegateDescriptorImpl && value.descriptor.containingDeclaration is ClassDescriptor)) {
|
||||
val thisPtr = evaluateExpression(value.receiver!!)
|
||||
return codegen.loadSlot(
|
||||
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
|
||||
@@ -1258,7 +1260,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
if (value.descriptor.dispatchReceiverParameter != null
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
|| value.descriptor is IrImplementingDelegateDescriptorImpl) {
|
||||
|| value.descriptor is IrImplementingDelegateDescriptorImpl
|
||||
|| (value.descriptor is IrPropertyDelegateDescriptorImpl && value.descriptor.containingDeclaration is ClassDescriptor)) {
|
||||
val thisPtr = evaluateExpression(value.receiver!!)
|
||||
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
|
||||
}
|
||||
|
||||
+3
-2
@@ -125,7 +125,7 @@ private fun ContextUtils.getDeclaredFields(classDescriptor: ClassDescriptor): Li
|
||||
}
|
||||
|
||||
private fun ContextUtils.createClassBodyType(name: String, fields: List<PropertyDescriptor>): LLVMTypeRef {
|
||||
val fieldTypes = fields.map { getLLVMType(it.type) }.toTypedArray()
|
||||
val fieldTypes = fields.map { getLLVMType(if (it.isDelegated) context.builtIns.nullableAnyType else it.type) }.toTypedArray()
|
||||
|
||||
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
|
||||
|
||||
@@ -300,7 +300,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiverParameter != null
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
|| descriptor is IrImplementingDelegateDescriptorImpl) {
|
||||
|| descriptor is IrImplementingDelegateDescriptorImpl
|
||||
|| (descriptor is IrPropertyDelegateDescriptorImpl && descriptor.containingDeclaration is ClassDescriptor)) {
|
||||
val containingClass = dispatchReceiverParameter?.containingDeclaration
|
||||
// TODO: hack because of IR bug: https://github.com/JetBrains/kotlin/tree/rr/dispatch_receiver_for_delegate_descriptor.
|
||||
?: descriptor.containingDeclaration
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ internal class MetadataGenerator(override val context: Context): ContextUtils {
|
||||
|
||||
internal fun property(declaration: IrProperty) {
|
||||
if (declaration.backingField == null) return
|
||||
assert(declaration.backingField!!.descriptor == declaration.descriptor)
|
||||
assert(declaration.backingField!!.descriptor == declaration.descriptor || declaration.isDelegated)
|
||||
|
||||
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
|
||||
}
|
||||
|
||||
+7
-67
@@ -13,8 +13,10 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -66,71 +68,6 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa
|
||||
}
|
||||
}
|
||||
|
||||
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
|
||||
IrDeclarationOriginImpl("BRIDGE_METHOD")
|
||||
|
||||
internal class DelegationLowering(val context: Context) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
irClass.declarations.transformFlat {
|
||||
when (it) {
|
||||
is IrFunction -> {
|
||||
val transformedFun = transformBridgeToDelegatedMethod(irClass, it)
|
||||
if (transformedFun == null) null
|
||||
else listOf(transformedFun)
|
||||
}
|
||||
is IrProperty -> {
|
||||
val getter = transformBridgeToDelegatedMethod(irClass, it.getter)
|
||||
val setter = transformBridgeToDelegatedMethod(irClass, it.setter)
|
||||
if (getter != null) it.getter = getter
|
||||
if (setter != null) it.setter = setter
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: hack because of broken IR for synthesized delegated members: https://youtrack.jetbrains.com/issue/KT-16486.
|
||||
private fun transformBridgeToDelegatedMethod(irClass: IrClass, irFunction: IrFunction?): IrFunction? {
|
||||
if (irFunction == null || irFunction.descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
|
||||
|
||||
val body = irFunction.body as? IrBlockBody
|
||||
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
|
||||
val statement = body.statements.single()
|
||||
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
|
||||
?: throw AssertionError("Unexpected method body: $statement")
|
||||
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
|
||||
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
|
||||
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
|
||||
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
|
||||
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
|
||||
OverriddenFunctionDescriptor(irFunction.descriptor, delegatedCall.descriptor as FunctionDescriptor))
|
||||
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, delegated)
|
||||
|
||||
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
|
||||
val returnType = delegatedCall.descriptor.returnType!!
|
||||
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
|
||||
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, irClass.descriptor.thisAsReceiverParameter)
|
||||
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
|
||||
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
|
||||
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
|
||||
}
|
||||
irCall.mapValueParameters { overriddenValueParameter ->
|
||||
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
|
||||
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
|
||||
}
|
||||
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
|
||||
irBlockBody.statements.add(irCall)
|
||||
} else {
|
||||
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
|
||||
irBlockBody.statements.add(irReturn)
|
||||
}
|
||||
|
||||
newFunction.body = irBlockBody
|
||||
return newFunction
|
||||
}
|
||||
}
|
||||
|
||||
internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
val functions = mutableSetOf<FunctionDescriptor?>()
|
||||
@@ -160,6 +97,9 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
|
||||
IrDeclarationOriginImpl("BRIDGE_METHOD")
|
||||
|
||||
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
|
||||
val bridgeDescriptor = context.specialDescriptorsFactory.getBridgeDescriptor(descriptor)
|
||||
val target = descriptor.descriptor.target
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.OverriddenFunctionDescriptor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
internal class ClassDelegationLowering(val context: Context) : DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.declarations.transformFlat {
|
||||
when (it) {
|
||||
is IrFunction -> {
|
||||
val transformedFun = transformBridgeToDelegatedMethod(irDeclarationContainer, it)
|
||||
if (transformedFun == null) null
|
||||
else listOf(transformedFun)
|
||||
}
|
||||
is IrProperty -> {
|
||||
val getter = transformBridgeToDelegatedMethod(irDeclarationContainer, it.getter)
|
||||
val setter = transformBridgeToDelegatedMethod(irDeclarationContainer, it.setter)
|
||||
if (getter != null) it.getter = getter
|
||||
if (setter != null) it.setter = setter
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformBridgeToDelegatedMethod(irDeclarationContainer: IrDeclarationContainer, irFunction: IrFunction?): IrFunction? {
|
||||
if (irFunction == null) return null
|
||||
val descriptor = irFunction.descriptor
|
||||
|
||||
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
|
||||
|
||||
// TODO: hack because of broken IR for synthesized delegated members: https://youtrack.jetbrains.com/issue/KT-16486.
|
||||
val body = irFunction.body as? IrBlockBody
|
||||
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
|
||||
val statement = body.statements.single()
|
||||
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
|
||||
?: throw AssertionError("Unexpected method body: $statement")
|
||||
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
|
||||
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
|
||||
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
|
||||
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
|
||||
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
|
||||
OverriddenFunctionDescriptor(descriptor, delegatedCall.descriptor as FunctionDescriptor))
|
||||
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, irFunction.origin, delegated)
|
||||
|
||||
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
|
||||
val returnType = delegatedCall.descriptor.returnType!!
|
||||
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
|
||||
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset,
|
||||
(irDeclarationContainer as IrClass).descriptor.thisAsReceiverParameter)
|
||||
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
|
||||
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
|
||||
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
|
||||
}
|
||||
irCall.mapValueParameters { overriddenValueParameter ->
|
||||
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
|
||||
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
|
||||
}
|
||||
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
|
||||
irBlockBody.statements.add(irCall)
|
||||
} else {
|
||||
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
|
||||
irBlockBody.statements.add(irReturn)
|
||||
}
|
||||
|
||||
newFunction.body = irBlockBody
|
||||
return newFunction
|
||||
}
|
||||
}
|
||||
|
||||
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
return super.visitFunction(declaration)
|
||||
}
|
||||
|
||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
val name = declaration.descriptor.name.asString()
|
||||
val type = declaration.descriptor.type
|
||||
|
||||
val initializer = declaration.delegate.initializer!!
|
||||
return IrVariableImpl(declaration.startOffset, declaration.endOffset,
|
||||
declaration.origin, declaration.delegate.descriptor,
|
||||
IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null,
|
||||
listOf(
|
||||
transformBridgeToDelegate(name, type, declaration.getter),
|
||||
transformBridgeToDelegate(name, type, declaration.setter),
|
||||
initializer
|
||||
).filterNotNull())
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.isDelegated) {
|
||||
val name = declaration.descriptor.name.asString()
|
||||
val type = declaration.descriptor.returnType!!
|
||||
declaration.getter = transformBridgeToDelegate(name, type, declaration.getter)
|
||||
declaration.setter = transformBridgeToDelegate(name, type, declaration.setter)
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
|
||||
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName.fromSegments(listOf("kotlin", "reflect")))
|
||||
private val genericKPropertyImplType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("KPropertyImpl"),
|
||||
NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
private fun transformBridgeToDelegate(name: String, type: KotlinType, irFunction: IrFunction?): IrFunction? {
|
||||
irFunction?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
|
||||
val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0]
|
||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(type)))
|
||||
val kPropertyImplType = genericKPropertyImplType.substitute(typeSubstitutor)
|
||||
return IrCallImpl(expression.startOffset, expression.endOffset,
|
||||
kPropertyImplType.defaultType, kPropertyImplType.unsubstitutedPrimaryConstructor!!, null).apply {
|
||||
putValueArgument(0, IrConstImpl<String>(expression.startOffset, expression.endOffset,
|
||||
context.builtIns.stringType, IrConstKind.String, name))
|
||||
}
|
||||
}
|
||||
})
|
||||
return irFunction
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user