Enum entries generation (no underlying classes yet)

This commit is contained in:
Dmitry Petrov
2016-08-31 15:03:40 +03:00
committed by Dmitry Petrov
parent 917e7bffbd
commit bd76e39a8c
16 changed files with 254 additions and 23 deletions
@@ -17,9 +17,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.*
@@ -146,6 +144,14 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
}
private fun generateSuperConstructorCall(irBlockBody: IrBlockBodyImpl, ktClassOrObject: KtClassOrObject) {
val classDescriptor = getOrFail(BindingContext.CLASS, ktClassOrObject)
if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
val kotlinEnumConstructor = context.builtIns.enum.unsubstitutedPrimaryConstructor!!
irBlockBody.addStatement(IrEnumConstructorCallImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, kotlinEnumConstructor))
return
}
val ktSuperTypeList = ktClassOrObject.getSuperTypeList() ?: return
for (ktSuperTypeListEntry in ktSuperTypeList.entries) {
if (ktSuperTypeListEntry is KtSuperTypeCallEntry) {
@@ -158,6 +164,23 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
}
}
fun generateEnumEntryInitializer(ktEnumEntry: KtEnumEntry, enumEntryDescriptor: ClassDescriptor): IrExpression {
val statementGenerator = createStatementGenerator()
val ktSuperCallElement = ktEnumEntry.getSuperTypeListEntries().firstOrNull()
if (ktSuperCallElement != null) {
val enumConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperCallElement)!!)
return CallGenerator(statementGenerator).generateEnumConstructorSuperCall(
ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumConstructorCall, enumEntryDescriptor)
}
// No-argument enum entry constructor
val enumClassDescriptor = enumEntryDescriptor.containingDeclaration as ClassDescriptor
val enumClassConstructor = enumClassDescriptor.unsubstitutedPrimaryConstructor!!
return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumClassConstructor, enumEntryDescriptor)
}
fun generateNestedInitializersBody(ktClassOrObject: KtClassOrObject): IrBody {
val irBody = IrBlockBodyImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset)
generateInitializersForClassBody(irBody, ktClassOrObject)
@@ -27,12 +27,7 @@ import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorExtension(statementGenerator) {
fun generateCall(
startOffset: Int,
endOffset: Int,
call: CallBuilder,
operator: IrOperator? = null
): IrExpression {
fun generateCall(startOffset: Int, endOffset: Int, call: CallBuilder, operator: IrOperator? = null): IrExpression {
val descriptor = call.descriptor
return when (descriptor) {
@@ -49,11 +44,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
}
}
fun generateDelegatingConstructorCall(
startOffset: Int,
endOffset: Int,
call: CallBuilder
) : IrExpression {
fun generateDelegatingConstructorCall(startOffset: Int, endOffset: Int, call: CallBuilder) : IrExpression {
val descriptor = call.descriptor
if (descriptor !is ConstructorDescriptor) throw AssertionError("Constructor expected: $descriptor")
@@ -61,11 +52,24 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
if (dispatchReceiver != null) throw AssertionError("Dispatch receiver should be null: $dispatchReceiver")
if (extensionReceiver != null) throw AssertionError("Extension receiver should be null: $extensionReceiver")
val irCall = IrDelegatingConstructorCallImpl(startOffset, endOffset, descriptor)
addParametersToCall(startOffset, endOffset, call, irCall, descriptor.returnType)
}
}
fun generateEnumConstructorSuperCall(startOffset: Int, endOffset: Int, call: CallBuilder, enumEntryDescriptor: ClassDescriptor) : IrExpression {
val constructorDescriptor = call.descriptor
if (constructorDescriptor !is ConstructorDescriptor) throw AssertionError("Constructor expected: $constructorDescriptor")
val classDescriptor = constructorDescriptor.containingDeclaration
if (classDescriptor.kind != ClassKind.ENUM_CLASS) throw AssertionError("Enum class constructor expected: $classDescriptor")
return call.callReceiver.call { dispatchReceiver, extensionReceiver ->
if (dispatchReceiver != null) throw AssertionError("Dispatch receiver should be null: $dispatchReceiver")
if (extensionReceiver != null) throw AssertionError("Extension receiver should be null: $extensionReceiver")
val irCall = IrEnumConstructorCallImpl(startOffset, endOffset, constructorDescriptor, enumEntryDescriptor)
addParametersToCall(startOffset, endOffset, call, irCall, constructorDescriptor.returnType)
}
}
private fun generatePropertyGetterCall(
descriptor: PropertyDescriptor,
startOffset: Int,
@@ -20,10 +20,7 @@ import org.jetbrains.kotlin.ir.declarations.*
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.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtSecondaryConstructor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.isConstructorDelegatingToSuper
@@ -105,4 +102,19 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
irProperty.valueInitializer = IrExpressionBodyImpl(ktParameter.startOffset, ktParameter.endOffset, irGetParameter)
return irProperty
}
fun generateEnumEntry(ktEnumEntry: KtEnumEntry): IrEnumEntry {
val enumEntryDescriptor = getOrFail(BindingContext.CLASS, ktEnumEntry)
val irEnumEntry = IrEnumEntryImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, IrDeclarationOrigin.DEFINED, enumEntryDescriptor)
irEnumEntry.initializerExpression =
BodyGenerator(enumEntryDescriptor.containingDeclaration, context)
.generateEnumEntryInitializer(ktEnumEntry, enumEntryDescriptor)
ktEnumEntry.getBody()?.let { ktEnumEntryBody ->
// TODO
}
return irEnumEntry
}
}
@@ -34,6 +34,8 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
generateSecondaryConstructor(ktDeclaration)
is KtProperty ->
generatePropertyDeclaration(ktDeclaration)
is KtEnumEntry ->
generateEnumEntryDeclaration(ktDeclaration)
is KtClassOrObject ->
generateClassOrObjectDeclaration(ktDeclaration)
is KtTypeAlias ->
@@ -45,6 +47,9 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
)
}
private fun generateEnumEntryDeclaration(ktEnumEntry: KtEnumEntry): IrEnumEntry =
ClassGenerator(this).generateEnumEntry(ktEnumEntry)
fun generateClassOrObjectDeclaration(ktClassOrObject: KtClassOrObject): IrClass =
ClassGenerator(this).generateClass(ktClassOrObject)
@@ -35,4 +35,6 @@ const val TRY_RESULT_SLOT = -1
const val FINALLY_EXPRESSION_SLOT = -2
const val NESTED_INITIALIZERS_SLOT = -1
const val PROPERTY_GETTER_SLOT = -1
const val PROPERTY_SETTER_SLOT = -2
const val PROPERTY_SETTER_SLOT = -2
const val ENUM_ENTRY_CLASS_SLOT = -1
const val ENUM_ENTRY_INITIALIZER_SLOT = -2
@@ -37,6 +37,7 @@ enum class IrDeclarationKind {
VARIABLE,
CLASS,
TYPEALIAS,
ENUM_ENTRY,
DUMMY;
}
@@ -0,0 +1,80 @@
/*
* 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.ClassDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrEnumEntry : IrDeclaration {
override val declarationKind: IrDeclarationKind get() = IrDeclarationKind.ENUM_ENTRY
override val descriptor: ClassDescriptor
var correspondingClass: IrClass?
var initializerExpression: IrExpression
}
class IrEnumEntryImpl(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
override val descriptor: ClassDescriptor
) : IrDeclarationBase(startOffset, endOffset, origin), IrEnumEntry {
override var correspondingClass: IrClass? = null
set(value) {
value?.assertDetached()
field?.detach()
field = value
value?.setTreeLocation(this, ENUM_ENTRY_CLASS_SLOT)
}
private var initializerExpressionImpl: IrExpression? = null
override var initializerExpression: IrExpression
get() = initializerExpressionImpl!!
set(value) {
value.assertDetached()
initializerExpressionImpl?.detach()
initializerExpressionImpl = value
value.setTreeLocation(this, ENUM_ENTRY_INITIALIZER_SLOT)
}
override fun getChild(slot: Int): IrElement? {
return when (slot) {
ENUM_ENTRY_CLASS_SLOT -> correspondingClass
ENUM_ENTRY_INITIALIZER_SLOT -> initializerExpression
else -> null
}
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
ENUM_ENTRY_CLASS_SLOT -> correspondingClass = newChild.assertCast()
ENUM_ENTRY_INITIALIZER_SLOT -> initializerExpression = newChild.assertCast()
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitEnumEntry(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
initializerExpression.accept(visitor, data)
correspondingClass?.accept(visitor, data)
}
}
@@ -0,0 +1,41 @@
/*
* 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.expressions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrEnumConstructorCall : IrGeneralCall {
override val descriptor: ConstructorDescriptor
val enumEntryDescriptor: ClassDescriptor?
}
val IrEnumConstructorCall.isDelegating: Boolean
get() = enumEntryDescriptor == null
class IrEnumConstructorCallImpl(
startOffset: Int,
endOffset: Int,
override val descriptor: ConstructorDescriptor,
override val enumEntryDescriptor: ClassDescriptor? = null
) : IrGeneralCallBase(startOffset, endOffset, descriptor.returnType, descriptor.valueParameters.size), IrEnumConstructorCall {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitEnumConstructorCall(this, data)
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceLocationManager
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -53,6 +54,13 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
}
}
override fun visitEnumEntry(declaration: IrEnumEntry, data: String) {
declaration.dumpLabeledElementWith(data) {
declaration.initializerExpression.accept(this, "init")
declaration.correspondingClass?.accept(this, "class")
}
}
override fun visitGeneralCall(expression: IrGeneralCall, data: String) {
expression.dumpLabeledElementWith(data) {
expression.dispatchReceiver?.accept(this, "\$this")
@@ -60,6 +60,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
"VAR ${declaration.descriptor.render()}"
override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String =
"ENUM_ENTRY ${declaration.descriptor.render()}"
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
"EXPRESSION_BODY"
@@ -100,6 +103,13 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String =
"DELEGATING_CONSTRUCTOR_CALL ${expression.descriptor.containingDeclaration.name}"
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String =
"ENUM_CONSTRUCTOR_CALL ${expression.descriptor.containingDeclaration.name} " +
expression.enumEntryDescriptor.let { enumEntryDescriptor ->
if (enumEntryDescriptor == null) "super"
else enumEntryDescriptor.name
}
override fun visitNestedInitializersCall(expression: IrNestedInitializersCall, data: Nothing?): String =
"NESTED_INITIALIZERS_CALL classDescriptor=${expression.classDescriptor.name}"
@@ -36,6 +36,7 @@ interface IrElementVisitor<out R, in D> {
fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data)
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
fun visitVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data)
fun visitEnumEntry(declaration: IrEnumEntry, data: D) = visitDeclaration(declaration, data)
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
@@ -62,6 +63,7 @@ interface IrElementVisitor<out R, in D> {
fun visitGeneralCall(expression: IrGeneralCall, data: D) = visitDeclarationReference(expression, data)
fun visitCall(expression: IrCall, data: D) = visitGeneralCall(expression, data)
fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: D) = visitGeneralCall(expression, data)
fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: D) = visitGeneralCall(expression, data)
fun visitCallableReference(expression: IrCallableReference, data: D) = visitDeclarationReference(expression, data)
fun visitNestedInitializersCall(expression: IrNestedInitializersCall, data: D) = visitExpression(expression, data)
+1
View File
@@ -12,3 +12,4 @@ FILE /classes.kt
CLASS ENUM_CLASS TestEnumClass
FUN private constructor TestEnumClass()
BLOCK_BODY
ENUM_CONSTRUCTOR_CALL Enum super
+9
View File
@@ -0,0 +1,9 @@
enum class TestEnum1 {
TEST1, TEST2
}
enum class TestEnum2(val x: Int) {
TEST1(1),
TEST2(2),
TEST3(3)
}
+27
View File
@@ -0,0 +1,27 @@
FILE /enum.kt
CLASS ENUM_CLASS TestEnum1
FUN private constructor TestEnum1()
BLOCK_BODY
ENUM_CONSTRUCTOR_CALL Enum super
ENUM_ENTRY enum entry TEST1
init: ENUM_CONSTRUCTOR_CALL TestEnum1 TEST1
ENUM_ENTRY enum entry TEST2
init: ENUM_CONSTRUCTOR_CALL TestEnum1 TEST2
CLASS ENUM_CLASS TestEnum2
FUN private constructor TestEnum2(/*0*/ x: kotlin.Int)
BLOCK_BODY
ENUM_CONSTRUCTOR_CALL Enum super
SET_BACKING_FIELD x type=kotlin.Unit operator=null
GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER
PROPERTY public final val x: kotlin.Int
EXPRESSION_BODY
GET_VAR x type=kotlin.Int operator=INITIALIZE_PROPERTY_FROM_PARAMETER
ENUM_ENTRY enum entry TEST1
init: ENUM_CONSTRUCTOR_CALL TestEnum2 TEST1
x: CONST Int type=kotlin.Int value='1'
ENUM_ENTRY enum entry TEST2
init: ENUM_CONSTRUCTOR_CALL TestEnum2 TEST2
x: CONST Int type=kotlin.Int value='2'
ENUM_ENTRY enum entry TEST3
init: ENUM_CONSTRUCTOR_CALL TestEnum2 TEST3
x: CONST Int type=kotlin.Int value='3'
+3 -3
View File
@@ -2,9 +2,9 @@ FILE /values.kt
CLASS ENUM_CLASS Enum
FUN private constructor Enum()
BLOCK_BODY
CLASS ENUM_ENTRY A
FUN private constructor A()
BLOCK_BODY
ENUM_CONSTRUCTOR_CALL Enum super
ENUM_ENTRY enum entry A
init: ENUM_CONSTRUCTOR_CALL Enum A
CLASS OBJECT A
FUN private constructor A()
BLOCK_BODY
@@ -79,6 +79,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("enum.kt")
public void testEnum() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/enum.kt");
doTest(fileName);
}
@TestMetadata("initVal.kt")
public void testInitVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/initVal.kt");