Implementing interface by delegation: creating delegates in class.

This commit is contained in:
Dmitry Petrov
2016-09-01 19:08:37 +03:00
committed by Dmitry Petrov
parent 264c8afc78
commit 2438876173
6 changed files with 105 additions and 11 deletions
@@ -18,10 +18,12 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrImplementingDelegateDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.IrGetVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -39,6 +41,8 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject)
generateMembersDeclaredInSupertypeList(irClass, ktClassOrObject)
generateMembersDeclaredInClassBody(irClass, ktClassOrObject)
if (descriptor.isData) {
@@ -52,6 +56,30 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
return irClass
}
private fun generateMembersDeclaredInSupertypeList(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
ktClassOrObject.getSuperTypeList()?.let { ktSuperTypeList ->
for (ktEntry in ktSuperTypeList.entries) {
if (ktEntry is KtDelegatedSuperTypeEntry) {
generateDelegatedImplementationMembers(irClass, ktEntry)
}
}
}
}
private fun generateDelegatedImplementationMembers(irClass: IrClassImpl, ktEntry: KtDelegatedSuperTypeEntry) {
val ktDelegateExpression = ktEntry.delegateExpression!!
val delegateType = getInferredTypeWithImplicitCastsOrFail(ktDelegateExpression)
val superType = getOrFail(BindingContext.TYPE, ktEntry.typeReference!!)
val delegateDescriptor = IrImplementingDelegateDescriptorImpl(irClass.descriptor, delegateType, superType)
val irDelegate = IrDelegateImpl(ktDelegateExpression.startOffset, ktDelegateExpression.endOffset, IrDeclarationOrigin.DELEGATE,
delegateDescriptor)
val bodyGenerator = BodyGenerator(irClass.descriptor, context)
irDelegate.initializer = bodyGenerator.generatePropertyInitializerBody(ktDelegateExpression)
irClass.addMember(irDelegate)
// TODO add delegated members
}
private fun generateAdditionalMembersForDataClass(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
DataClassMembersGenerator(ktClassOrObject, context, irClass).generate()
}
@@ -121,7 +121,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
propertyDescriptor.dispatchReceiverParameter?.type
val kPropertyType = context.reflectionTypes.getKPropertyType(
Annotations.EMPTY, propertyReceiverType, propertyDescriptor.type, propertyDescriptor.isVar)
val delegateDescriptor = IrPropertyDelegateDescriptorImpl(delegateType, propertyDescriptor, kPropertyType)
val delegateDescriptor = IrPropertyDelegateDescriptorImpl(propertyDescriptor, delegateType, kPropertyType)
val irDelegateInitializer = generateInitializerBody(delegateDescriptor, ktDelegateExpression)
val irDelegate = IrDelegateImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE,
delegateDescriptor, irDelegateInitializer)
@@ -31,16 +31,15 @@ interface IrPropertyDelegateDescriptor : IrDelegateDescriptor {
val kPropertyType: KotlinType
}
class IrPropertyDelegateDescriptorImpl(
outType: KotlinType,
override val correspondingProperty: PropertyDescriptor,
override val kPropertyType: KotlinType
) : IrPropertyDelegateDescriptor,
VariableDescriptorImpl(correspondingProperty.containingDeclaration,
Annotations.EMPTY,
getDelegateName(correspondingProperty.name),
outType, SourceElement.NO_SOURCE
) {
interface IrImplementingDelegateDescriptor : IrDelegateDescriptor {
val correspondingSuperType: KotlinType
}
abstract class IrDelegateDescriptorBase(
containingDeclaration: DeclarationDescriptor,
name: Name,
delegateType: KotlinType
) : VariableDescriptorImpl(containingDeclaration, Annotations.EMPTY, name, delegateType, SourceElement.NO_SOURCE) {
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
override fun getVisibility(): Visibility = Visibilities.PRIVATE
@@ -55,5 +54,24 @@ class IrPropertyDelegateDescriptorImpl(
visitor.visitVariableDescriptor(this, data)
}
class IrPropertyDelegateDescriptorImpl(
override val correspondingProperty: PropertyDescriptor,
delegateType: KotlinType,
override val kPropertyType: KotlinType
) : IrPropertyDelegateDescriptor,
IrDelegateDescriptorBase(correspondingProperty.containingDeclaration, getDelegateName(correspondingProperty.name), delegateType)
class IrImplementingDelegateDescriptorImpl(
containingDeclaration: ClassDescriptor,
delegateType: KotlinType,
override val correspondingSuperType: KotlinType
) : IrImplementingDelegateDescriptor,
IrDelegateDescriptorBase(containingDeclaration, getDelegateName(containingDeclaration, correspondingSuperType), delegateType)
internal fun getDelegateName(name: Name): Name =
Name.identifier(name.asString() + "\$delegate")
internal fun getDelegateName(classDescriptor: ClassDescriptor, superType: KotlinType): Name =
Name.identifier(classDescriptor.name.asString() + "\$" +
(superType.constructor.declarationDescriptor?.name ?: "\$") +
"\$delegate")
@@ -0,0 +1,9 @@
interface IBase
object BaseImpl : IBase
interface IOther
fun otherImpl(): IOther = object : IOther {}
class Test1 : IBase by BaseImpl
class Test2 : IBase by BaseImpl, IOther by otherImpl()
@@ -0,0 +1,33 @@
FILE /delegatedImplementation.kt
CLASS INTERFACE IBase
CLASS OBJECT BaseImpl
CONSTRUCTOR private constructor BaseImpl()
BLOCK_BODY
INSTANCE_INITIALIZER_CALL classDescriptor=BaseImpl
CLASS INTERFACE IOther
FUN public fun otherImpl(): IOther
BLOCK_BODY
RETURN type=kotlin.Nothing from=otherImpl
BLOCK type=otherImpl.<no name provided> operator=OBJECT_LITERAL
CLASS CLASS <no name provided>
CONSTRUCTOR public constructor <no name provided>()
BLOCK_BODY
INSTANCE_INITIALIZER_CALL classDescriptor=<no name provided>
CALL .<init> type=otherImpl.<no name provided> operator=OBJECT_LITERAL
CLASS CLASS Test1
CONSTRUCTOR public constructor Test1()
BLOCK_BODY
INSTANCE_INITIALIZER_CALL classDescriptor=Test1
DELEGATE val `Test1$IBase$delegate`: BaseImpl
EXPRESSION_BODY
GET_OBJECT BaseImpl type=BaseImpl
CLASS CLASS Test2
CONSTRUCTOR public constructor Test2()
BLOCK_BODY
INSTANCE_INITIALIZER_CALL classDescriptor=Test2
DELEGATE val `Test2$IBase$delegate`: BaseImpl
EXPRESSION_BODY
GET_OBJECT BaseImpl type=BaseImpl
DELEGATE val `Test2$IOther$delegate`: IOther
EXPRESSION_BODY
CALL .otherImpl type=IOther operator=null
@@ -73,6 +73,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("delegatedImplementation.kt")
public void testDelegatedImplementation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatedImplementation.kt");
doTest(fileName);
}
@TestMetadata("delegatingConstructorCallsInSecondaryConstructors.kt")
public void testDelegatingConstructorCallsInSecondaryConstructors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatingConstructorCallsInSecondaryConstructors.kt");