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.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.IrExpressionBodyImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetVariableImpl
|
import org.jetbrains.kotlin.ir.expressions.IrGetVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
@@ -39,6 +41,8 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
|
|||||||
|
|
||||||
generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject)
|
generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject)
|
||||||
|
|
||||||
|
generateMembersDeclaredInSupertypeList(irClass, ktClassOrObject)
|
||||||
|
|
||||||
generateMembersDeclaredInClassBody(irClass, ktClassOrObject)
|
generateMembersDeclaredInClassBody(irClass, ktClassOrObject)
|
||||||
|
|
||||||
if (descriptor.isData) {
|
if (descriptor.isData) {
|
||||||
@@ -52,6 +56,30 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
|
|||||||
return irClass
|
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) {
|
private fun generateAdditionalMembersForDataClass(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
|
||||||
DataClassMembersGenerator(ktClassOrObject, context, irClass).generate()
|
DataClassMembersGenerator(ktClassOrObject, context, irClass).generate()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
|
|||||||
propertyDescriptor.dispatchReceiverParameter?.type
|
propertyDescriptor.dispatchReceiverParameter?.type
|
||||||
val kPropertyType = context.reflectionTypes.getKPropertyType(
|
val kPropertyType = context.reflectionTypes.getKPropertyType(
|
||||||
Annotations.EMPTY, propertyReceiverType, propertyDescriptor.type, propertyDescriptor.isVar)
|
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 irDelegateInitializer = generateInitializerBody(delegateDescriptor, ktDelegateExpression)
|
||||||
val irDelegate = IrDelegateImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE,
|
val irDelegate = IrDelegateImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE,
|
||||||
delegateDescriptor, irDelegateInitializer)
|
delegateDescriptor, irDelegateInitializer)
|
||||||
|
|||||||
+28
-10
@@ -31,16 +31,15 @@ interface IrPropertyDelegateDescriptor : IrDelegateDescriptor {
|
|||||||
val kPropertyType: KotlinType
|
val kPropertyType: KotlinType
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrPropertyDelegateDescriptorImpl(
|
interface IrImplementingDelegateDescriptor : IrDelegateDescriptor {
|
||||||
outType: KotlinType,
|
val correspondingSuperType: KotlinType
|
||||||
override val correspondingProperty: PropertyDescriptor,
|
}
|
||||||
override val kPropertyType: KotlinType
|
|
||||||
) : IrPropertyDelegateDescriptor,
|
abstract class IrDelegateDescriptorBase(
|
||||||
VariableDescriptorImpl(correspondingProperty.containingDeclaration,
|
containingDeclaration: DeclarationDescriptor,
|
||||||
Annotations.EMPTY,
|
name: Name,
|
||||||
getDelegateName(correspondingProperty.name),
|
delegateType: KotlinType
|
||||||
outType, SourceElement.NO_SOURCE
|
) : VariableDescriptorImpl(containingDeclaration, Annotations.EMPTY, name, delegateType, SourceElement.NO_SOURCE) {
|
||||||
) {
|
|
||||||
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
|
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
|
||||||
|
|
||||||
override fun getVisibility(): Visibility = Visibilities.PRIVATE
|
override fun getVisibility(): Visibility = Visibilities.PRIVATE
|
||||||
@@ -55,5 +54,24 @@ class IrPropertyDelegateDescriptorImpl(
|
|||||||
visitor.visitVariableDescriptor(this, data)
|
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 =
|
internal fun getDelegateName(name: Name): Name =
|
||||||
Name.identifier(name.asString() + "\$delegate")
|
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);
|
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")
|
@TestMetadata("delegatingConstructorCallsInSecondaryConstructors.kt")
|
||||||
public void testDelegatingConstructorCallsInSecondaryConstructors() throws Exception {
|
public void testDelegatingConstructorCallsInSecondaryConstructors() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatingConstructorCallsInSecondaryConstructors.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatingConstructorCallsInSecondaryConstructors.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user