From d27f22ae0e995bd2b13f4073b9641f3318544942 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 1 Sep 2016 19:39:46 +0300 Subject: [PATCH] Delegated implementations for functions and extension functions. --- .../generators/ArgumentsGenerationUtils.kt | 2 +- .../psi2ir/generators/ClassGenerator.kt | 69 +++++++++++++++++-- .../psi2ir/generators/StatementGenerator.kt | 6 +- .../kotlin/ir/declarations/IrDeclaration.kt | 1 + .../ir/expressions/IrGetExtensionReceiver.kt | 6 +- .../irText/classes/delegatedImplementation.kt | 13 +++- .../classes/delegatedImplementation.txt | 43 ++++++++++++ 7 files changed, 121 insertions(+), 19 deletions(-) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index d2c9bfd25e1..048c03838c7 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -51,7 +51,7 @@ fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: R IrGetObjectValueImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type, receiver.classQualifier.descriptor) is ExtensionReceiver -> - IrGetExtensionReceiverImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset, receiver.type, + IrGetExtensionReceiverImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset, receiver.declarationDescriptor.extensionReceiverParameter!!) else -> TODO("Receiver: ${receiver.javaClass.simpleName}") 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 20b71bcf565..693b808671b 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 @@ -16,12 +16,11 @@ package org.jetbrains.kotlin.psi2ir.generators -import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* 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.ir.expressions.* import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtEnumEntry @@ -29,6 +28,8 @@ import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import java.lang.AssertionError class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator { override val context: GeneratorContext get() = declarationGenerator.context @@ -58,18 +59,28 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator private fun generateMembersDeclaredInSupertypeList(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { ktClassOrObject.getSuperTypeList()?.let { ktSuperTypeList -> + val delegatedMembers = irClass.descriptor.unsubstitutedMemberScope + .getContributedDescriptors(DescriptorKindFilter.CALLABLES) + .filterIsInstance() + .filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION } + if (delegatedMembers.isEmpty()) return + for (ktEntry in ktSuperTypeList.entries) { if (ktEntry is KtDelegatedSuperTypeEntry) { - generateDelegatedImplementationMembers(irClass, ktEntry) + generateDelegatedImplementationMembers(irClass, ktEntry, delegatedMembers) } } } } - private fun generateDelegatedImplementationMembers(irClass: IrClassImpl, ktEntry: KtDelegatedSuperTypeEntry) { + private fun generateDelegatedImplementationMembers(irClass: IrClassImpl, ktEntry: KtDelegatedSuperTypeEntry, + delegatedMembers: List) { val ktDelegateExpression = ktEntry.delegateExpression!! val delegateType = getInferredTypeWithImplicitCastsOrFail(ktDelegateExpression) val superType = getOrFail(BindingContext.TYPE, ktEntry.typeReference!!) + val superTypeConstructorDescriptor = superType.constructor.declarationDescriptor + val superClass = superTypeConstructorDescriptor as? ClassDescriptor ?: + throw AssertionError("Unexpected supertype constructor for delegation: $superTypeConstructorDescriptor") val delegateDescriptor = IrImplementingDelegateDescriptorImpl(irClass.descriptor, delegateType, superType) val irDelegate = IrDelegateImpl(ktDelegateExpression.startOffset, ktDelegateExpression.endOffset, IrDeclarationOrigin.DELEGATE, delegateDescriptor) @@ -77,7 +88,51 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator irDelegate.initializer = bodyGenerator.generatePropertyInitializerBody(ktDelegateExpression) irClass.addMember(irDelegate) - // TODO add delegated members + for (delegatedMember in delegatedMembers) { + val overriddenMember = delegatedMember.overriddenDescriptors.find { it.containingDeclaration.original == superClass.original } + if (overriddenMember != null) { + generateDelegatedMember(irClass, irDelegate, delegatedMember, overriddenMember) + } + } + } + + private fun generateDelegatedMember(irClass: IrClassImpl, irDelegate: IrDelegateImpl, delegatedMember: CallableMemberDescriptor, overriddenMember: CallableMemberDescriptor) { + when (delegatedMember) { + is FunctionDescriptor -> + generateDelegatedFunction(irClass, irDelegate, delegatedMember, overriddenMember as FunctionDescriptor) + is PropertyDescriptor -> + generateDelegatedProperty(irClass, irDelegate, delegatedMember, overriddenMember as PropertyDescriptor) + } + + } + + private fun generateDelegatedProperty(irClass: IrClassImpl, irDelegate: IrDelegateImpl, delegated: PropertyDescriptor, overridden: PropertyDescriptor) { + // TODO + } + + private fun generateDelegatedFunction(irClass: IrClassImpl, irDelegate: IrDelegateImpl, delegated: FunctionDescriptor, overridden: FunctionDescriptor) { + val irFunction = IrFunctionImpl(irDelegate.startOffset, irDelegate.endOffset, IrDeclarationOrigin.DELEGATED_MEMBER, delegated) + val irBlockBody = IrBlockBodyImpl(irDelegate.startOffset, irDelegate.endOffset) + + val returnType = overridden.returnType!! + val irCall = IrCallImpl(irDelegate.startOffset, irDelegate.endOffset, returnType, overridden) + irCall.dispatchReceiver = IrGetVariableImpl(irDelegate.startOffset, irDelegate.endOffset, irDelegate.descriptor) + irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver -> + IrGetExtensionReceiverImpl(irDelegate.startOffset, irDelegate.endOffset, extensionReceiver) + } + irCall.mapValueParameters { overriddenValueParameter -> + val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index] + IrGetVariableImpl(irDelegate.startOffset, irDelegate.endOffset, delegatedValueParameter) + } + if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) { + irBlockBody.addStatement(irCall) + } + else { + irBlockBody.addStatement(IrReturnImpl(irDelegate.startOffset, irDelegate.endOffset, context.builtIns.nothingType, delegated, irCall)) + } + + irFunction.body = irBlockBody + irClass.addMember(irFunction) } private fun generateAdditionalMembersForDataClass(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index da3b3f2b8de..2b154af4444 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -285,11 +285,7 @@ class StatementGenerator( ) is CallableDescriptor -> { val extensionReceiver = referenceTarget.extensionReceiverParameter ?: TODO("No extension receiver: $referenceTarget") - IrGetExtensionReceiverImpl( - expression.startOffset, expression.endOffset, - extensionReceiver.type, - extensionReceiver - ) + IrGetExtensionReceiverImpl(expression.startOffset, expression.endOffset, extensionReceiver) } else -> error("Expected this or receiver: $referenceTarget") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index 0c96a7f47ec..2cbb32261a0 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -47,6 +47,7 @@ enum class IrDeclarationOrigin { DEFINED, DELEGATE, DELEGATED_PROPERTY_ACCESSOR, + DELEGATED_MEMBER, CLASS_FOR_ENUM_ENTRY, ENUM_CLASS_SPECIAL_MEMBER, GENERATED_DATA_CLASS_MEMBER, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGetExtensionReceiver.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGetExtensionReceiver.kt index ee7fe9dc59a..b6d1d6c29f9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGetExtensionReceiver.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrGetExtensionReceiver.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.ir.expressions import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor -import org.jetbrains.kotlin.types.KotlinType interface IrGetExtensionReceiver : IrDeclarationReference, IrExpressionWithCopy { override val descriptor: ReceiverParameterDescriptor @@ -29,12 +28,11 @@ interface IrGetExtensionReceiver : IrDeclarationReference, IrExpressionWithCopy class IrGetExtensionReceiverImpl( startOffset: Int, endOffset: Int, - type: KotlinType, descriptor: ReceiverParameterDescriptor -) : IrTerminalDeclarationReferenceBase(startOffset, endOffset, type, descriptor), IrGetExtensionReceiver { +) : IrTerminalDeclarationReferenceBase(startOffset, endOffset, descriptor.type, descriptor), IrGetExtensionReceiver { override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitGetExtensionReceiver(this, data) override fun copy(): IrGetExtensionReceiver = - IrGetExtensionReceiverImpl(startOffset, endOffset, type, descriptor) + IrGetExtensionReceiverImpl(startOffset, endOffset, descriptor) } diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.kt b/compiler/testData/ir/irText/classes/delegatedImplementation.kt index 75f596bf061..a596c971916 100644 --- a/compiler/testData/ir/irText/classes/delegatedImplementation.kt +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.kt @@ -1,5 +1,14 @@ -interface IBase -object BaseImpl : IBase +interface IBase { + fun foo(x: Int, s: String) + fun bar(): Int + fun String.qux() +} + +object BaseImpl : IBase { + override fun foo(x: Int, s: String) {} + override fun bar(): Int = 42 + override fun String.qux() {} +} interface IOther fun otherImpl(): IOther = object : IOther {} diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.txt b/compiler/testData/ir/irText/classes/delegatedImplementation.txt index 6c6fc5c5c02..81ccc16072b 100644 --- a/compiler/testData/ir/irText/classes/delegatedImplementation.txt +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.txt @@ -1,9 +1,20 @@ FILE /delegatedImplementation.kt CLASS INTERFACE IBase + FUN public abstract fun foo(/*0*/ x: kotlin.Int, /*1*/ s: kotlin.String): kotlin.Unit + FUN public abstract fun bar(): kotlin.Int + FUN public abstract fun kotlin.String.qux(): kotlin.Unit CLASS OBJECT BaseImpl CONSTRUCTOR private constructor BaseImpl() BLOCK_BODY INSTANCE_INITIALIZER_CALL classDescriptor=BaseImpl + FUN public open override /*1*/ fun foo(/*0*/ x: kotlin.Int, /*1*/ s: kotlin.String): kotlin.Unit + BLOCK_BODY + FUN public open override /*1*/ fun bar(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from=bar + CONST Int type=kotlin.Int value='42' + FUN public open override /*1*/ fun kotlin.String.qux(): kotlin.Unit + BLOCK_BODY CLASS INTERFACE IOther FUN public fun otherImpl(): IOther BLOCK_BODY @@ -21,6 +32,22 @@ FILE /delegatedImplementation.kt DELEGATE val `Test1$IBase$delegate`: BaseImpl EXPRESSION_BODY GET_OBJECT BaseImpl type=BaseImpl + FUN public open override /*1*/ /*delegation*/ fun foo(/*0*/ x: kotlin.Int, /*1*/ s: kotlin.String): kotlin.Unit + BLOCK_BODY + CALL .foo type=kotlin.Unit operator=null + $this: GET_VAR Test1$IBase$delegate type=BaseImpl operator=null + x: GET_VAR x type=kotlin.Int operator=null + s: GET_VAR s type=kotlin.String operator=null + FUN public open override /*1*/ /*delegation*/ fun bar(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from=bar + CALL .bar type=kotlin.Int operator=null + $this: GET_VAR Test1$IBase$delegate type=BaseImpl operator=null + FUN public open override /*1*/ /*delegation*/ fun kotlin.String.qux(): kotlin.Unit + BLOCK_BODY + CALL .qux type=kotlin.Unit operator=null + $this: GET_VAR Test1$IBase$delegate type=BaseImpl operator=null + $receiver: $RECEIVER of: qux type=kotlin.String CLASS CLASS Test2 CONSTRUCTOR public constructor Test2() BLOCK_BODY @@ -28,6 +55,22 @@ FILE /delegatedImplementation.kt DELEGATE val `Test2$IBase$delegate`: BaseImpl EXPRESSION_BODY GET_OBJECT BaseImpl type=BaseImpl + FUN public open override /*1*/ /*delegation*/ fun foo(/*0*/ x: kotlin.Int, /*1*/ s: kotlin.String): kotlin.Unit + BLOCK_BODY + CALL .foo type=kotlin.Unit operator=null + $this: GET_VAR Test2$IBase$delegate type=BaseImpl operator=null + x: GET_VAR x type=kotlin.Int operator=null + s: GET_VAR s type=kotlin.String operator=null + FUN public open override /*1*/ /*delegation*/ fun bar(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from=bar + CALL .bar type=kotlin.Int operator=null + $this: GET_VAR Test2$IBase$delegate type=BaseImpl operator=null + FUN public open override /*1*/ /*delegation*/ fun kotlin.String.qux(): kotlin.Unit + BLOCK_BODY + CALL .qux type=kotlin.Unit operator=null + $this: GET_VAR Test2$IBase$delegate type=BaseImpl operator=null + $receiver: $RECEIVER of: qux type=kotlin.String DELEGATE val `Test2$IOther$delegate`: IOther EXPRESSION_BODY CALL .otherImpl type=IOther operator=null