diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt index 8ab6f180fa0..20b71bcf565 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ClassGenerator.kt @@ -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() } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt index ed67a9b9640..4728cb4ab6f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt @@ -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) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt index f68647a1e4d..7a0a344a683 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt @@ -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") \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.kt b/compiler/testData/ir/irText/classes/delegatedImplementation.kt new file mode 100644 index 00000000000..75f596bf061 --- /dev/null +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.kt @@ -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() \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.txt b/compiler/testData/ir/irText/classes/delegatedImplementation.txt new file mode 100644 index 00000000000..6c6fc5c5c02 --- /dev/null +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.txt @@ -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. operator=OBJECT_LITERAL + CLASS CLASS + CONSTRUCTOR public constructor () + BLOCK_BODY + INSTANCE_INITIALIZER_CALL classDescriptor= + CALL . type=otherImpl. 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 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 682ca8dd2b8..f58cd7f14d6 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -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");