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 693b808671b..47f0cfa01ff 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 @@ -29,7 +29,6 @@ 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 @@ -107,13 +106,29 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator } private fun generateDelegatedProperty(irClass: IrClassImpl, irDelegate: IrDelegateImpl, delegated: PropertyDescriptor, overridden: PropertyDescriptor) { - // TODO + val irProperty = IrSimplePropertyImpl(irDelegate.startOffset, irDelegate.endOffset, IrDeclarationOrigin.DELEGATED_MEMBER, delegated) + + val irGetter = IrPropertyGetterImpl(irDelegate.startOffset, irDelegate.endOffset, IrDeclarationOrigin.DELEGATED_MEMBER, delegated.getter!!) + irGetter.body = generateDelegateFunctionBody(irDelegate, delegated.getter!!, overridden.getter!!) + irProperty.getter = irGetter + + if (delegated.isVar) { + val irSetter = IrPropertySetterImpl(irDelegate.startOffset, irDelegate.endOffset, IrDeclarationOrigin.DELEGATED_MEMBER, delegated.setter!!) + irSetter.body = generateDelegateFunctionBody(irDelegate, delegated.setter!!, overridden.setter!!) + irProperty.setter = irSetter + } + + irClass.addMember(irProperty) } 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) + irFunction.body = generateDelegateFunctionBody(irDelegate, delegated, overridden) + irClass.addMember(irFunction) + } + private fun generateDelegateFunctionBody(irDelegate: IrDelegateImpl, delegated: FunctionDescriptor, overridden: FunctionDescriptor): IrBlockBodyImpl { + 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) @@ -128,11 +143,10 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator irBlockBody.addStatement(irCall) } else { - irBlockBody.addStatement(IrReturnImpl(irDelegate.startOffset, irDelegate.endOffset, context.builtIns.nothingType, delegated, irCall)) + val irReturn = IrReturnImpl(irDelegate.startOffset, irDelegate.endOffset, context.builtIns.nothingType, delegated, irCall) + irBlockBody.addStatement(irReturn) } - - irFunction.body = irBlockBody - irClass.addMember(irFunction) + return irBlockBody } private fun generateAdditionalMembersForDataClass(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrPropertyAccessor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrPropertyAccessor.kt index 09b4f1c0e2a..8721d12cf87 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrPropertyAccessor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrPropertyAccessor.kt @@ -43,17 +43,25 @@ interface IrPropertySetter : IrPropertyAccessor { abstract class IrPropertyAccessorBase( startOffset: Int, endOffset: Int, - origin: IrDeclarationOrigin, - body: IrBody -) : IrGeneralFunctionBase(startOffset, endOffset, origin, body), IrPropertyAccessor + origin: IrDeclarationOrigin +) : IrGeneralFunctionBase(startOffset, endOffset, origin), IrPropertyAccessor class IrPropertyGetterImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - override val descriptor: PropertyGetterDescriptor, - body: IrBody -) : IrPropertyAccessorBase(startOffset, endOffset, origin, body), IrPropertyGetter { + override val descriptor: PropertyGetterDescriptor +) : IrPropertyAccessorBase(startOffset, endOffset, origin), IrPropertyGetter { + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: PropertyGetterDescriptor, + body: IrBody + ) : this(startOffset, endOffset, origin, descriptor) { + this.body = body + } + override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitPropertyGetter(this, data) } @@ -62,9 +70,18 @@ class IrPropertySetterImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - override val descriptor: PropertySetterDescriptor, - body: IrBody -) : IrPropertyAccessorBase(startOffset, endOffset, origin, body), IrPropertySetter { + override val descriptor: PropertySetterDescriptor +) : IrPropertyAccessorBase(startOffset, endOffset, origin), IrPropertySetter { + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: PropertySetterDescriptor, + body: IrBody + ) : this(startOffset, endOffset, origin, descriptor) { + this.body = body + } + override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitPropertySetter(this, data) } \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.kt b/compiler/testData/ir/irText/classes/delegatedImplementation.kt index a596c971916..c5c17b1381d 100644 --- a/compiler/testData/ir/irText/classes/delegatedImplementation.kt +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.kt @@ -10,9 +10,22 @@ object BaseImpl : IBase { override fun String.qux() {} } -interface IOther -fun otherImpl(): IOther = object : IOther {} +interface IOther { + val x: String + var y: Int + val Byte.z1: Int + var Byte.z2: Int +} + +fun otherImpl(x0: String, y0: Int): IOther = object : IOther { + override val x: String = x0 + override var y: Int = y0 + override val Byte.z1: Int get() = 1 + override var Byte.z2: Int + get() = 2 + set(value) {} +} class Test1 : IBase by BaseImpl -class Test2 : IBase by BaseImpl, IOther by otherImpl() \ No newline at end of file +class Test2 : IBase by BaseImpl, IOther by otherImpl("", 42) \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/delegatedImplementation.txt b/compiler/testData/ir/irText/classes/delegatedImplementation.txt index 81ccc16072b..b295c93498a 100644 --- a/compiler/testData/ir/irText/classes/delegatedImplementation.txt +++ b/compiler/testData/ir/irText/classes/delegatedImplementation.txt @@ -16,7 +16,11 @@ FILE /delegatedImplementation.kt FUN public open override /*1*/ fun kotlin.String.qux(): kotlin.Unit BLOCK_BODY CLASS INTERFACE IOther - FUN public fun otherImpl(): IOther + PROPERTY public abstract val x: kotlin.String + PROPERTY public abstract var y: kotlin.Int + PROPERTY public abstract val kotlin.Byte.z1: kotlin.Int + PROPERTY public abstract var kotlin.Byte.z2: kotlin.Int + FUN public fun otherImpl(/*0*/ x0: kotlin.String, /*1*/ y0: kotlin.Int): IOther BLOCK_BODY RETURN type=kotlin.Nothing from=otherImpl BLOCK type=otherImpl. operator=OBJECT_LITERAL @@ -24,6 +28,24 @@ FILE /delegatedImplementation.kt CONSTRUCTOR public constructor () BLOCK_BODY INSTANCE_INITIALIZER_CALL classDescriptor= + PROPERTY public open override /*1*/ val x: kotlin.String + EXPRESSION_BODY + GET_VAR x0 type=kotlin.String operator=null + PROPERTY public open override /*1*/ var y: kotlin.Int + EXPRESSION_BODY + GET_VAR y0 type=kotlin.Int operator=null + PROPERTY public open override /*1*/ val kotlin.Byte.z1: kotlin.Int + PROPERTY_GETTER public open override /*1*/ fun kotlin.Byte.(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CONST Int type=kotlin.Int value='1' + PROPERTY public open override /*1*/ var kotlin.Byte.z2: kotlin.Int + PROPERTY_GETTER public open override /*1*/ fun kotlin.Byte.(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CONST Int type=kotlin.Int value='2' + PROPERTY_SETTER public open override /*1*/ fun kotlin.Byte.(/*0*/ value: kotlin.Int): kotlin.Unit + BLOCK_BODY CALL . type=otherImpl. operator=OBJECT_LITERAL CLASS CLASS Test1 CONSTRUCTOR public constructor Test1() @@ -74,3 +96,42 @@ FILE /delegatedImplementation.kt DELEGATE val `Test2$IOther$delegate`: IOther EXPRESSION_BODY CALL .otherImpl type=IOther operator=null + x0: CONST String type=kotlin.String value='' + y0: CONST Int type=kotlin.Int value='42' + PROPERTY public open override /*1*/ /*delegation*/ val x: kotlin.String + PROPERTY_GETTER public open override /*1*/ /*delegation*/ fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL . type=kotlin.String operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + PROPERTY public open override /*1*/ /*delegation*/ var y: kotlin.Int + PROPERTY_GETTER public open override /*1*/ /*delegation*/ fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL . type=kotlin.Int operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + PROPERTY_SETTER public open override /*1*/ /*delegation*/ fun (/*0*/ : kotlin.Int): kotlin.Unit + BLOCK_BODY + CALL . type=kotlin.Unit operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + : GET_VAR type=kotlin.Int operator=null + PROPERTY public open override /*1*/ /*delegation*/ val kotlin.Byte.z1: kotlin.Int + PROPERTY_GETTER public open override /*1*/ /*delegation*/ fun kotlin.Byte.(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL . type=kotlin.Int operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + $receiver: $RECEIVER of: z1 type=kotlin.Byte + PROPERTY public open override /*1*/ /*delegation*/ var kotlin.Byte.z2: kotlin.Int + PROPERTY_GETTER public open override /*1*/ /*delegation*/ fun kotlin.Byte.(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL . type=kotlin.Int operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + $receiver: $RECEIVER of: z2 type=kotlin.Byte + PROPERTY_SETTER public open override /*1*/ /*delegation*/ fun kotlin.Byte.(/*0*/ : kotlin.Int): kotlin.Unit + BLOCK_BODY + CALL . type=kotlin.Unit operator=null + $this: GET_VAR Test2$IOther$delegate type=IOther operator=null + $receiver: $RECEIVER of: z2 type=kotlin.Byte + : GET_VAR type=kotlin.Int operator=null diff --git a/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.kt b/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.kt new file mode 100644 index 00000000000..be4947207ed --- /dev/null +++ b/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.kt @@ -0,0 +1,13 @@ +interface IFooBar { + fun foo() + fun bar() +} + +object FooBarImpl : IFooBar { + override fun foo() {} + override fun bar() {} +} + +class C : IFooBar by FooBarImpl { + override fun bar() {} +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.txt b/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.txt new file mode 100644 index 00000000000..276fe1b78f3 --- /dev/null +++ b/compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.txt @@ -0,0 +1,25 @@ +FILE /delegatedImplementationWithExplicitOverride.kt + CLASS INTERFACE IFooBar + FUN public abstract fun foo(): kotlin.Unit + FUN public abstract fun bar(): kotlin.Unit + CLASS OBJECT FooBarImpl + CONSTRUCTOR private constructor FooBarImpl() + BLOCK_BODY + INSTANCE_INITIALIZER_CALL classDescriptor=FooBarImpl + FUN public open override /*1*/ fun foo(): kotlin.Unit + BLOCK_BODY + FUN public open override /*1*/ fun bar(): kotlin.Unit + BLOCK_BODY + CLASS CLASS C + CONSTRUCTOR public constructor C() + BLOCK_BODY + INSTANCE_INITIALIZER_CALL classDescriptor=C + DELEGATE val `C$IFooBar$delegate`: FooBarImpl + EXPRESSION_BODY + GET_OBJECT FooBarImpl type=FooBarImpl + FUN public open override /*1*/ /*delegation*/ fun foo(): kotlin.Unit + BLOCK_BODY + CALL .foo type=kotlin.Unit operator=null + $this: GET_VAR C$IFooBar$delegate type=FooBarImpl operator=null + FUN public open override /*1*/ fun bar(): kotlin.Unit + BLOCK_BODY diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index f58cd7f14d6..da69652946b 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -79,6 +79,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("delegatedImplementationWithExplicitOverride.kt") + public void testDelegatedImplementationWithExplicitOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatedImplementationWithExplicitOverride.kt"); + doTest(fileName); + } + @TestMetadata("delegatingConstructorCallsInSecondaryConstructors.kt") public void testDelegatingConstructorCallsInSecondaryConstructors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/delegatingConstructorCallsInSecondaryConstructors.kt");