From 703d3405edee3330ac6e6d37caa83954ab7d863e Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 25 Aug 2016 18:33:12 +0300 Subject: [PATCH] Generate class members (functions, properties, nested classes). --- .../psi2ir/generators/ClassGenerator.kt | 38 ++++++++++++-- .../psi2ir/generators/DeclarationGenerator.kt | 51 ++++++------------- .../kotlin/ir/declarations/IrConstructor.kt | 50 ++++++++++++++++++ .../kotlin/ir/declarations/IrFunction.kt | 43 ++++++++++------ .../kotlin/ir/visitors/IrElementVisitor.kt | 1 + .../ir/irText/arrayAugmentedAssignment1.txt | 1 + .../ir/irText/arrayAugmentedAssignment2.txt | 2 + compiler/testData/ir/irText/assignments.txt | 1 + .../testData/ir/irText/chainOfSafeCalls.txt | 8 +++ .../ir/irText/conventionComparisons.txt | 1 + .../ir/irText/forWithImplicitReceivers.txt | 26 ++++++++++ compiler/testData/ir/irText/safeCalls.txt | 6 +++ compiler/testData/ir/irText/values.txt | 2 + 13 files changed, 174 insertions(+), 56 deletions(-) create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt 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 99b7233c8e6..56987d44325 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,10 +16,9 @@ package org.jetbrains.kotlin.psi2ir.generators -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrClassImpl -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.psi.KtClassOrObject +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 @@ -30,7 +29,38 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator fun generateClass(ktClassOrObject: KtClassOrObject): IrClass { val descriptor = getOrFail(BindingContext.CLASS, ktClassOrObject) val irClass = IrClassImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, IrDeclarationOrigin.DEFINED, descriptor) - // TODO generate members + + generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject) + generateMembersDeclaredInClassbody(irClass, ktClassOrObject) + return irClass } + + private fun generatePropertiesDeclaredInPrimaryConstructor(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { + ktClassOrObject.getPrimaryConstructor()?.let { ktPrimaryConstructor -> + for (ktParameter in ktPrimaryConstructor.valueParameters) { + if (ktParameter.hasValOrVar()) { + irClass.addMember(generatePropertyForPrimaryConstructorParameter(ktParameter)) + } + } + } + } + + private fun generateMembersDeclaredInClassbody(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { + ktClassOrObject.getBody()?.let { ktClassBody -> + for (ktDeclaration in ktClassBody.declarations) { + val irMember = declarationGenerator.generateMemberDeclaration(ktDeclaration) + irClass.addMember(irMember) + if (irMember is IrProperty) { + irMember.getter?.let { irClass.addMember(it) } + irMember.setter?.let { irClass.addMember(it) } + } + } + } + } + + private fun generatePropertyForPrimaryConstructorParameter(ktParameter: KtParameter): IrDeclaration { + val propertyDescriptor = getOrFail(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, ktParameter) + return IrSimplePropertyImpl(ktParameter.startOffset, ktParameter.endOffset, IrDeclarationOrigin.DEFINED, propertyDescriptor) + } } 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 b3c2ccd70b7..c217865c8d9 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 @@ -49,62 +49,41 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator { IrTypeAliasImpl(ktDeclaration.startOffset, ktDeclaration.endOffset, IrDeclarationOrigin.DEFINED, getOrFail(BindingContext.TYPE_ALIAS, ktDeclaration)) - fun generateFunctionDeclaration(ktNamedFunction: KtNamedFunction): IrFunction { - val functionDescriptor = getOrFail(BindingContext.FUNCTION, ktNamedFunction) - val body = generateFunctionBody(functionDescriptor, ktNamedFunction.bodyExpression ?: TODO("function without body expression")) - return createFunction(ktNamedFunction, functionDescriptor, body) + fun generateFunctionDeclaration(ktFunction: KtNamedFunction): IrFunction { + val functionDescriptor = getOrFail(BindingContext.FUNCTION, ktFunction) + val body = ktFunction.bodyExpression?.let { generateFunctionBody(functionDescriptor, it) } + return IrFunctionImpl(ktFunction.startOffset, ktFunction.endOffset, IrDeclarationOrigin.DEFINED, + functionDescriptor, body) } fun generatePropertyDeclaration(ktProperty: KtProperty): IrProperty { val propertyDescriptor = getPropertyDescriptor(ktProperty) if (ktProperty.hasDelegate()) TODO("handle delegated property") val initializer = ktProperty.initializer?.let { generateInitializerBody(propertyDescriptor, it) } - val irProperty = createSimpleProperty(ktProperty, propertyDescriptor, initializer) + val irProperty = IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED, + propertyDescriptor, initializer) ktProperty.getter?.let { ktGetter -> val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktGetter) val getterDescriptor = accessorDescriptor as? PropertyGetterDescriptor ?: TODO("not a getter?") - val getterBody = generateFunctionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter")) - createPropertyGetter(ktGetter, irProperty, getterDescriptor, getterBody) + val irGetterBody = generateFunctionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter")) + val irGetter = IrPropertyGetterImpl(ktGetter.startOffset, ktGetter.endOffset, IrDeclarationOrigin.DEFINED, + getterDescriptor, irGetterBody) + irProperty.getter = irGetter } ktProperty.setter?.let { ktSetter -> val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktSetter) val setterDescriptor = accessorDescriptor as? PropertySetterDescriptor ?: TODO("not a setter?") - val setterBody = generateFunctionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter")) - createPropertySetter(ktSetter, irProperty, setterDescriptor, setterBody) + val irSetterBody = generateFunctionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter")) + val irSetter = IrPropertySetterImpl(ktSetter.startOffset, ktSetter.endOffset, IrDeclarationOrigin.DEFINED, + setterDescriptor, irSetterBody) + irProperty.setter = irSetter } return irProperty } - fun createFunction(ktFunction: KtFunction, functionDescriptor: FunctionDescriptor, body: IrBody): IrFunction = - IrFunctionImpl(ktFunction.startOffset, ktFunction.endOffset, - IrDeclarationOrigin.DEFINED, functionDescriptor, body) - - fun createSimpleProperty(ktProperty: KtProperty, propertyDescriptor: PropertyDescriptor, valueInitializer: IrBody?): IrSimpleProperty = - IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset, - IrDeclarationOrigin.DEFINED, propertyDescriptor, valueInitializer) - - fun createPropertyGetter( - ktPropertyAccessor: KtPropertyAccessor, - irProperty: IrProperty, - getterDescriptor: PropertyGetterDescriptor, - getterBody: IrBody - ): IrPropertyGetter = - IrPropertyGetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset, - IrDeclarationOrigin.DEFINED, getterDescriptor, getterBody) - .apply { irProperty.getter = this } - - fun createPropertySetter( - ktPropertyAccessor: KtPropertyAccessor, - irProperty: IrProperty, - setterDescriptor: PropertySetterDescriptor, - setterBody: IrBody - ) : IrPropertySetter = - IrPropertySetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset, - IrDeclarationOrigin.DEFINED, setterDescriptor, setterBody) - .apply { irProperty.setter = this } private fun getPropertyDescriptor(ktProperty: KtProperty): PropertyDescriptor { val variableDescriptor = getOrFail(BindingContext.VARIABLE, ktProperty) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt new file mode 100644 index 00000000000..2e17b1ebd75 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.ir.declarations + +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + + +interface IrConstructor : IrFunction { + override val declarationKind: IrDeclarationKind + get() = IrDeclarationKind.CONSTRUCTOR + + override val descriptor: ConstructorDescriptor +} + +class IrConstructorImpl( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + override val descriptor: ConstructorDescriptor +) : IrFunctionBase(startOffset, endOffset, origin), IrConstructor { + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: ConstructorDescriptor, + body: IrBody + ) : this(startOffset, endOffset, origin, descriptor) { + this.body = body + } + + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitConstructor(this, data) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt index 3a27c00b7ce..7f9df31e052 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFunction.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor interface IrFunction : IrDeclaration { override val descriptor: FunctionDescriptor - val body: IrBody + val body: IrBody? override val declarationKind: IrDeclarationKind get() = IrDeclarationKind.FUNCTION @@ -32,21 +32,23 @@ interface IrFunction : IrDeclaration { abstract class IrFunctionBase( startOffset: Int, endOffset: Int, - origin: IrDeclarationOrigin, - body: IrBody? = null + origin: IrDeclarationOrigin ) : IrDeclarationBase(startOffset, endOffset, origin), IrFunction { - init { - body?.setTreeLocation(this, FUNCTION_BODY_SLOT) + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + body: IrBody + ) : this(startOffset, endOffset, origin) { + this.body = body } - private var bodyImpl: IrBody? = body - override var body: IrBody - get() = bodyImpl!! + final override var body: IrBody? = null set(newValue) { - newValue.assertDetached() - bodyImpl?.detach() - bodyImpl = newValue - newValue.setTreeLocation(this, FUNCTION_BODY_SLOT) + newValue?.assertDetached() + field?.detach() + field = newValue + newValue?.setTreeLocation(this, FUNCTION_BODY_SLOT) } override fun getChild(slot: Int): IrElement? = @@ -63,7 +65,7 @@ abstract class IrFunctionBase( } override fun acceptChildren(visitor: IrElementVisitor, data: D) { - body.accept(visitor, data) + body?.accept(visitor, data) } } @@ -71,9 +73,18 @@ class IrFunctionImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - override val descriptor: FunctionDescriptor, - body: IrBody -) : IrFunctionBase(startOffset, endOffset, origin, body) { + override val descriptor: FunctionDescriptor +) : IrFunctionBase(startOffset, endOffset, origin) { + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: FunctionDescriptor, + body: IrBody? + ) : this(startOffset, endOffset, origin, descriptor) { + this.body = body + } + override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitFunction(this, data) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt index ca1296049ef..6063f67c0d0 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt @@ -31,6 +31,7 @@ interface IrElementVisitor { fun visitFunction(declaration: IrFunction, data: D): R = visitDeclaration(declaration, data) fun visitPropertyGetter(declaration: IrPropertyGetter, data: D): R = visitFunction(declaration, data) fun visitPropertySetter(declaration: IrPropertySetter, data: D): R = visitFunction(declaration, data) + fun visitConstructor(declaration: IrConstructor, data: D): R = visitFunction(declaration, data) fun visitProperty(declaration: IrProperty, data: D): R = visitDeclaration(declaration, data) fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data) fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data) diff --git a/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt b/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt index dc7bccbc8ec..855df049542 100644 --- a/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt +++ b/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt @@ -12,6 +12,7 @@ FILE /arrayAugmentedAssignment1.kt RETURN type=kotlin.Nothing CONST Int type=kotlin.Int value='42' CLASS CLASS C + PROPERTY public final val x: kotlin.IntArray getter=null setter=null FUN public fun testVariable(): kotlin.Unit BLOCK_BODY VAR var x: kotlin.IntArray diff --git a/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt b/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt index aad780f0538..63377c643ae 100644 --- a/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt +++ b/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt @@ -1,6 +1,8 @@ FILE /arrayAugmentedAssignment2.kt CLASS INTERFACE IA + FUN public abstract operator fun get(/*0*/ index: kotlin.String): kotlin.Int CLASS INTERFACE IB + FUN public abstract operator fun IA.set(/*0*/ index: kotlin.String, /*1*/ value: kotlin.Int): kotlin.Unit FUN public fun IB.test(/*0*/ a: IA): kotlin.Unit BLOCK_BODY BLOCK type=kotlin.Unit operator=PLUSEQ diff --git a/compiler/testData/ir/irText/assignments.txt b/compiler/testData/ir/irText/assignments.txt index f4dda6a3c8b..da420633288 100644 --- a/compiler/testData/ir/irText/assignments.txt +++ b/compiler/testData/ir/irText/assignments.txt @@ -1,5 +1,6 @@ FILE /assignments.kt CLASS CLASS Ref + PROPERTY public final var x: kotlin.Int getter=null setter=null FUN public fun test1(): kotlin.Unit BLOCK_BODY VAR var x: kotlin.Int diff --git a/compiler/testData/ir/irText/chainOfSafeCalls.txt b/compiler/testData/ir/irText/chainOfSafeCalls.txt index 599eeeb4e17..7ecfc4ccf72 100644 --- a/compiler/testData/ir/irText/chainOfSafeCalls.txt +++ b/compiler/testData/ir/irText/chainOfSafeCalls.txt @@ -1,5 +1,13 @@ FILE /chainOfSafeCalls.kt CLASS CLASS C + FUN public final fun foo(): C + BLOCK_BODY + RETURN type=kotlin.Nothing + THIS public final class C type=C + FUN public final fun bar(): C? + BLOCK_BODY + RETURN type=kotlin.Nothing + THIS public final class C type=C FUN public fun test(/*0*/ nc: C?): C? BLOCK_BODY RETURN type=kotlin.Nothing diff --git a/compiler/testData/ir/irText/conventionComparisons.txt b/compiler/testData/ir/irText/conventionComparisons.txt index 6b06bbef88d..99bed0bca10 100644 --- a/compiler/testData/ir/irText/conventionComparisons.txt +++ b/compiler/testData/ir/irText/conventionComparisons.txt @@ -1,6 +1,7 @@ FILE /conventionComparisons.kt CLASS INTERFACE IA CLASS INTERFACE IB + FUN public abstract operator fun IA.compareTo(/*0*/ other: IA): kotlin.Int FUN public fun IB.test1(/*0*/ a1: IA, /*1*/ a2: IA): kotlin.Boolean BLOCK_BODY RETURN type=kotlin.Nothing diff --git a/compiler/testData/ir/irText/forWithImplicitReceivers.txt b/compiler/testData/ir/irText/forWithImplicitReceivers.txt index 2bfb0e5e13b..fc02909bc14 100644 --- a/compiler/testData/ir/irText/forWithImplicitReceivers.txt +++ b/compiler/testData/ir/irText/forWithImplicitReceivers.txt @@ -1,7 +1,33 @@ FILE /forWithImplicitReceivers.kt CLASS OBJECT FiveTimes CLASS CLASS IntCell + PROPERTY public final var value: kotlin.Int getter=null setter=null CLASS INTERFACE IReceiver + FUN public open operator fun FiveTimes.iterator(): IntCell + BLOCK_BODY + RETURN type=kotlin.Nothing + CALL . type=IntCell operator=null + value: CONST Int type=kotlin.Int value='5' + FUN public open operator fun IntCell.hasNext(): kotlin.Boolean + BLOCK_BODY + RETURN type=kotlin.Nothing + CALL .GT0 type=kotlin.Boolean operator=GT + arg0: CALL .compareTo type=kotlin.Int operator=GT + $this: CALL . type=kotlin.Int operator=GET_PROPERTY + $this: $RECEIVER of: hasNext type=IntCell + other: CONST Int type=kotlin.Int value='0' + FUN public open operator fun IntCell.next(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing + BLOCK type=kotlin.Int operator=POSTFIX_DECR + VAR val tmp0: kotlin.Int + CALL . type=kotlin.Int operator=POSTFIX_DECR + $this: $RECEIVER of: next type=IntCell + CALL . type=kotlin.Unit operator=POSTFIX_DECR + $this: $RECEIVER of: next type=IntCell + : CALL .dec type=kotlin.Int operator=POSTFIX_DECR + $this: GET_VAR tmp0 type=kotlin.Int operator=null + GET_VAR tmp0 type=kotlin.Int operator=null FUN public fun IReceiver.test(): kotlin.Unit BLOCK_BODY BLOCK type=kotlin.Unit operator=FOR_LOOP diff --git a/compiler/testData/ir/irText/safeCalls.txt b/compiler/testData/ir/irText/safeCalls.txt index 86e4115f0c4..2d3661c7183 100644 --- a/compiler/testData/ir/irText/safeCalls.txt +++ b/compiler/testData/ir/irText/safeCalls.txt @@ -1,6 +1,12 @@ FILE /safeCalls.kt CLASS CLASS Ref + PROPERTY public final var value: kotlin.Int getter=null setter=null CLASS INTERFACE IHost + FUN public open fun kotlin.String.extLength(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing + CALL . type=kotlin.Int operator=GET_PROPERTY + $this: $RECEIVER of: extLength type=kotlin.String FUN public fun test1(/*0*/ x: kotlin.String?): kotlin.Int? BLOCK_BODY RETURN type=kotlin.Nothing diff --git a/compiler/testData/ir/irText/values.txt b/compiler/testData/ir/irText/values.txt index edbe0e8d05a..92beb48cf3a 100644 --- a/compiler/testData/ir/irText/values.txt +++ b/compiler/testData/ir/irText/values.txt @@ -1,10 +1,12 @@ FILE /values.kt CLASS ENUM_CLASS Enum + CLASS ENUM_ENTRY A CLASS OBJECT A PROPERTY public val a: kotlin.Int = 0 getter=null setter=null EXPRESSION_BODY CONST Int type=kotlin.Int value='0' CLASS CLASS Z + CLASS OBJECT Companion FUN public fun test1(): Enum BLOCK_BODY RETURN type=kotlin.Nothing