Implementing interface by delegation: creating delegates in class.
This commit is contained in:
committed by
Dmitry Petrov
parent
264c8afc78
commit
2438876173
@@ -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()
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+28
-10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user