Secondary constructors in classes.

This commit is contained in:
Dmitry Petrov
2016-08-26 14:08:52 +03:00
committed by Dmitry Petrov
parent ac80195597
commit 225d792939
13 changed files with 105 additions and 87 deletions
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtLoopExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import java.util.* import java.util.*
@@ -36,38 +33,19 @@ class BodyGenerator(val scopeOwner: CallableDescriptor, override val context: Ge
val irBlockBody = IrBlockBodyImpl(ktBody.startOffset, ktBody.endOffset) val irBlockBody = IrBlockBodyImpl(ktBody.startOffset, ktBody.endOffset)
if (ktBody is KtBlockExpression) { if (ktBody is KtBlockExpression) {
for (ktStatement in ktBody.statements) { statementGenerator.generateBlockBodyStatements(irBlockBody, ktBody)
irBlockBody.addStatement(statementGenerator.generateStatement(ktStatement))
}
} }
else { else {
val irBodyExpression = statementGenerator.generateExpression(ktBody) statementGenerator.generateReturnExpression(ktBody, irBlockBody)
irBlockBody.addStatement(irBodyExpression.wrapWithReturn())
} }
return irBlockBody return irBlockBody
} }
private fun IrExpression.wrapWithReturn() =
if (KotlinBuiltIns.isNothing(type))
this
else
IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scopeOwner, this)
fun generatePropertyInitializerBody(ktInitializer: KtExpression): IrBody = fun generatePropertyInitializerBody(ktInitializer: KtExpression): IrBody =
IrExpressionBodyImpl(ktInitializer.startOffset, ktInitializer.endOffset, IrExpressionBodyImpl(ktInitializer.startOffset, ktInitializer.endOffset,
createStatementGenerator().generateExpression(ktInitializer)) createStatementGenerator().generateExpression(ktInitializer))
private fun createStatementGenerator() =
StatementGenerator(context, scopeOwner, this, scope)
fun putLoop(expression: KtLoopExpression, irLoop: IrLoop) {
loopTable[expression] = irLoop
}
fun getLoop(expression: KtExpression): IrLoop? =
loopTable[expression]
fun generateLambdaBody(ktFun: KtFunctionLiteral): IrBody { fun generateLambdaBody(ktFun: KtFunctionLiteral): IrBody {
val statementGenerator = createStatementGenerator() val statementGenerator = createStatementGenerator()
@@ -78,13 +56,57 @@ class BodyGenerator(val scopeOwner: CallableDescriptor, override val context: Ge
irBlockBody.addStatement(statementGenerator.generateStatement(ktStatement)) irBlockBody.addStatement(statementGenerator.generateStatement(ktStatement))
} }
val ktReturnedValue = ktBody.statements.last() val ktReturnedValue = ktBody.statements.last()
irBlockBody.addStatement(statementGenerator.generateExpression(ktReturnedValue).wrapWithReturn()) statementGenerator.generateReturnExpression(ktReturnedValue, irBlockBody)
}
else {
irBlockBody.addStatement(statementGenerator.generateExpression(ktBody).wrapWithReturn())
} }
return irBlockBody return irBlockBody
} }
private fun StatementGenerator.generateBlockBodyStatements(irBlockBody: IrBlockBodyImpl, ktBody: KtBlockExpression) {
for (ktStatement in ktBody.statements) {
irBlockBody.addStatement(generateStatement(ktStatement))
}
}
private fun StatementGenerator.generateReturnExpression(ktExpression: KtExpression, irBlockBody: IrBlockBodyImpl) {
val irExpression = generateExpression(ktExpression)
irBlockBody.addStatement(irExpression.wrapWithReturn())
}
private fun IrExpression.wrapWithReturn() =
if (KotlinBuiltIns.isNothing(type))
this
else
IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scopeOwner, this)
fun generateSecondaryConstructorBody(ktConstructor: KtSecondaryConstructor): IrBody {
val statementGenerator = createStatementGenerator()
val irBlockBody = IrBlockBodyImpl(ktConstructor.startOffset, ktConstructor.endOffset)
val ktDelegatingConstructorCall = ktConstructor.getDelegationCall()
val delegatingConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktDelegatingConstructorCall)!!)
val irDelegatingConstructorCall = CallGenerator(statementGenerator).generateCall(
ktDelegatingConstructorCall, delegatingConstructorCall, IrOperator.DELEGATING_CONSTRUCTOR_CALL)
irBlockBody.addStatement(irDelegatingConstructorCall)
val ktBody = ktConstructor.bodyExpression
if (ktBody != null) {
statementGenerator.generateBlockBodyStatements(irBlockBody, ktBody)
}
return irBlockBody
}
private fun createStatementGenerator() =
StatementGenerator(context, scopeOwner, this, scope)
fun putLoop(expression: KtLoopExpression, irLoop: IrLoop) {
loopTable[expression] = irLoop
}
fun getLoop(expression: KtExpression): IrLoop? =
loopTable[expression]
} }
@@ -31,7 +31,7 @@ class BranchingExpressionGenerator(val statementGenerator: StatementGenerator) :
override val context: GeneratorContext get() = statementGenerator.context override val context: GeneratorContext get() = statementGenerator.context
fun generateIfExpression(expression: KtIfExpression): IrExpression { fun generateIfExpression(expression: KtIfExpression): IrExpression {
val resultType = getInferredTypeWithSmartcastsOrFail(expression) val resultType = getInferredTypeWithImplicitCastsOrFail(expression)
var ktLastIf: KtIfExpression = expression var ktLastIf: KtIfExpression = expression
val irBranches = SmartList<Pair<IrExpression, IrExpression>>() val irBranches = SmartList<Pair<IrExpression, IrExpression>>()
@@ -74,7 +74,7 @@ class BranchingExpressionGenerator(val statementGenerator: StatementGenerator) :
scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject") scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject")
} }
val resultType = getInferredTypeWithSmartcastsOrFail(expression) val resultType = getInferredTypeWithImplicitCastsOrFail(expression)
val irWhen = IrWhenImpl(expression.startOffset, expression.endOffset, resultType, IrOperator.WHEN) val irWhen = IrWhenImpl(expression.startOffset, expression.endOffset, resultType, IrOperator.WHEN)
@@ -31,7 +31,7 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
val irClass = IrClassImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, IrDeclarationOrigin.DEFINED, descriptor) val irClass = IrClassImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, IrDeclarationOrigin.DEFINED, descriptor)
generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject) generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject)
generateMembersDeclaredInClassbody(irClass, ktClassOrObject) generateMembersDeclaredInClassBody(irClass, ktClassOrObject)
return irClass return irClass
} }
@@ -46,7 +46,7 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
} }
} }
private fun generateMembersDeclaredInClassbody(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) { private fun generateMembersDeclaredInClassBody(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
ktClassOrObject.getBody()?.let { ktClassBody -> ktClassOrObject.getBody()?.let { ktClassBody ->
for (ktDeclaration in ktClassBody.declarations) { for (ktDeclaration in ktClassBody.declarations) {
val irMember = declarationGenerator.generateMemberDeclaration(ktDeclaration) val irMember = declarationGenerator.generateMemberDeclaration(ktDeclaration)
@@ -29,6 +29,8 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
when (ktDeclaration) { when (ktDeclaration) {
is KtNamedFunction -> is KtNamedFunction ->
generateFunctionDeclaration(ktDeclaration) generateFunctionDeclaration(ktDeclaration)
is KtSecondaryConstructor ->
generateSecondaryConstructor(ktDeclaration)
is KtProperty -> is KtProperty ->
generatePropertyDeclaration(ktDeclaration) generatePropertyDeclaration(ktDeclaration)
is KtClassOrObject -> is KtClassOrObject ->
@@ -56,6 +58,13 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
functionDescriptor, body) functionDescriptor, body)
} }
fun generateSecondaryConstructor(ktConstructor: KtSecondaryConstructor) : IrFunction {
val constructorDescriptor = getOrFail(BindingContext.CONSTRUCTOR, ktConstructor)
val body = BodyGenerator(constructorDescriptor, context).generateSecondaryConstructorBody(ktConstructor)
return IrFunctionImpl(ktConstructor.startOffset, ktConstructor.endOffset, IrDeclarationOrigin.DEFINED,
constructorDescriptor, body)
}
fun generatePropertyDeclaration(ktProperty: KtProperty): IrProperty { fun generatePropertyDeclaration(ktProperty: KtProperty): IrProperty {
val propertyDescriptor = getPropertyDescriptor(ktProperty) val propertyDescriptor = getPropertyDescriptor(ktProperty)
if (ktProperty.hasDelegate()) TODO("handle delegated property") if (ktProperty.hasDelegate()) TODO("handle delegated property")
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.expressions.IrDummyExpression import org.jetbrains.kotlin.ir.expressions.IrDummyExpression
import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -54,50 +51,14 @@ fun <K, V : Any> Generator.getOrFail(slice: ReadOnlySlice<K, V>, key: K): V =
inline fun <K, V : Any> Generator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V = inline fun <K, V : Any> Generator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V =
context.bindingContext[slice, key] ?: throw RuntimeException(message(key)) context.bindingContext[slice, key] ?: throw RuntimeException(message(key))
fun Generator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? = fun Generator.getInferredTypeWithImplicitCasts(key: KtExpression): KotlinType? =
context.bindingContext.getType(key) context.bindingContext.getType(key)
fun Generator.getInferredTypeWithSmartcastsOrFail(key: KtExpression): KotlinType = fun Generator.getInferredTypeWithImplicitCastsOrFail(key: KtExpression): KotlinType =
getInferredTypeWithSmartcasts(key) ?: throw AssertionError("No type for expression: ${key.text}") getInferredTypeWithImplicitCasts(key) ?: throw AssertionError("No type for expression: ${key.text}")
fun Generator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? = fun Generator.getResolvedCall(key: KtElement): ResolvedCall<out CallableDescriptor>? =
key.getResolvedCall(context.bindingContext) key.getResolvedCall(context.bindingContext)
fun Generator.getReturnType(key: KtExpression): KotlinType? {
val resolvedCall = getResolvedCall(key)
if (resolvedCall != null) {
return getReturnType(resolvedCall)
}
return when (key) {
is KtBlockExpression ->
getReturnType(key.statements.last())
is KtConstantExpression ->
getInferredTypeWithSmartcasts(key)
is KtStringTemplateExpression ->
context.builtIns.stringType
else ->
throw AssertionError("Unexpected expression: $key")
}
}
fun getReturnType(resolvedCall: ResolvedCall<*>): KotlinType {
val returnType = getReturnType(resolvedCall.resultingDescriptor)
return if (resolvedCall.call.isSafeCall()) returnType.makeNullable() else returnType
}
fun getReturnType(descriptor: CallableDescriptor): KotlinType {
return when (descriptor) {
is ClassDescriptor ->
descriptor.classValueType ?: throw AssertionError("Class descriptor without companion object: $descriptor")
is CallableDescriptor -> {
descriptor.returnType ?: throw AssertionError("Callable descriptor without return type: $descriptor")
}
else ->
throw AssertionError("Unexpected descriptor in resolved call: $descriptor")
}
}
fun Generator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression = fun Generator.createDummyExpression(ktExpression: KtExpression, description: String): IrDummyExpression =
IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithSmartcastsOrFail(ktExpression), description) IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithImplicitCastsOrFail(ktExpression), description)
@@ -35,7 +35,7 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener
fun generateLambda(ktLambda: KtLambdaExpression): IrStatement { fun generateLambda(ktLambda: KtLambdaExpression): IrStatement {
val ktFun = ktLambda.functionLiteral val ktFun = ktLambda.functionLiteral
val lambdaExpressionType = getInferredTypeWithSmartcastsOrFail(ktLambda) val lambdaExpressionType = getInferredTypeWithImplicitCastsOrFail(ktLambda)
val lambdaDescriptor = getOrFail(BindingContext.FUNCTION, ktFun) val lambdaDescriptor = getOrFail(BindingContext.FUNCTION, ktFun)
val irBlock = IrBlockImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType, IrOperator.LAMBDA) val irBlock = IrBlockImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType, IrOperator.LAMBDA)
@@ -54,7 +54,7 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener
} }
else { else {
// anonymous function expression // anonymous function expression
val funExpressionType = getInferredTypeWithSmartcastsOrFail(ktFun) val funExpressionType = getInferredTypeWithImplicitCastsOrFail(ktFun)
val irBlock = IrBlockImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType, IrOperator.ANONYMOUS_FUNCTION) val irBlock = IrBlockImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType, IrOperator.ANONYMOUS_FUNCTION)
val irFun = generateFunctionDeclaration(ktFun) val irFun = generateFunctionDeclaration(ktFun)
@@ -109,7 +109,7 @@ class StatementGenerator(
val isBlockBody = expression.parent is KtDeclarationWithBody && expression.parent !is KtFunctionLiteral val isBlockBody = expression.parent is KtDeclarationWithBody && expression.parent !is KtFunctionLiteral
if (isBlockBody) throw AssertionError("Use IrBlockBody and corresponding body generator to generate blocks as function bodies") if (isBlockBody) throw AssertionError("Use IrBlockBody and corresponding body generator to generate blocks as function bodies")
val returnType = getInferredTypeWithSmartcasts(expression) ?: context.builtIns.unitType val returnType = getInferredTypeWithImplicitCasts(expression) ?: context.builtIns.unitType
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, returnType) val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, returnType)
expression.statements.forEach { expression.statements.forEach {
@@ -151,7 +151,7 @@ class StatementGenerator(
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression { override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext) val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
?: error("KtConstantExpression was not evaluated: ${expression.text}") ?: error("KtConstantExpression was not evaluated: ${expression.text}")
val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithSmartcastsOrFail(expression)) val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithImplicitCastsOrFail(expression))
val constantType = constantValue.type val constantType = constantValue.type
return when (constantValue) { return when (constantValue) {
@@ -179,12 +179,12 @@ class StatementGenerator(
} }
entries.size == 0 -> { entries.size == 0 -> {
return IrConstImpl.string(expression.startOffset, expression.endOffset, return IrConstImpl.string(expression.startOffset, expression.endOffset,
getInferredTypeWithSmartcastsOrFail(expression), "") getInferredTypeWithImplicitCastsOrFail(expression), "")
} }
} }
val irStringTemplate = IrStringConcatenationImpl(expression.startOffset, expression.endOffset, val irStringTemplate = IrStringConcatenationImpl(expression.startOffset, expression.endOffset,
getInferredTypeWithSmartcastsOrFail(expression)) getInferredTypeWithImplicitCastsOrFail(expression))
entries.forEach { it.expression!!.let { irStringTemplate.addArgument(it.genExpr()) } } entries.forEach { it.expression!!.let { irStringTemplate.addArgument(it.genExpr()) } }
return irStringTemplate return irStringTemplate
} }
@@ -229,7 +229,7 @@ class StatementGenerator(
IrGetVariableImpl(expression.startOffset, expression.endOffset, descriptor) IrGetVariableImpl(expression.startOffset, expression.endOffset, descriptor)
else -> else ->
IrDummyExpression( IrDummyExpression(
expression.startOffset, expression.endOffset, getInferredTypeWithSmartcastsOrFail(expression), expression.startOffset, expression.endOffset, getInferredTypeWithImplicitCastsOrFail(expression),
expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}" expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}"
) )
} }
@@ -28,7 +28,7 @@ class TryCatchExpressionGenerator(val statementGenerator: StatementGenerator) :
override val context: GeneratorContext get() = statementGenerator.context override val context: GeneratorContext get() = statementGenerator.context
fun generateTryCatch(ktTry: KtTryExpression): IrExpression { fun generateTryCatch(ktTry: KtTryExpression): IrExpression {
val resultType = getInferredTypeWithSmartcastsOrFail(ktTry) val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry)
val irTryCatch = IrTryCatchImpl(ktTry.startOffset, ktTry.endOffset, resultType) val irTryCatch = IrTryCatchImpl(ktTry.startOffset, ktTry.endOffset, resultType)
irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock) irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock)
@@ -88,6 +88,8 @@ interface IrOperator {
object LAMBDA : IrOperatorImpl("LAMBDA") object LAMBDA : IrOperatorImpl("LAMBDA")
object ANONYMOUS_FUNCTION : IrOperatorImpl("ANONYMOUS_FUNCTION") object ANONYMOUS_FUNCTION : IrOperatorImpl("ANONYMOUS_FUNCTION")
object DELEGATING_CONSTRUCTOR_CALL : IrOperatorImpl("DELEGATING_CONSTRUCTOR_CALL")
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") { data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
companion object { companion object {
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) } private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
+6 -1
View File
@@ -2,7 +2,12 @@ FILE /classMembers.kt
CLASS CLASS C CLASS CLASS C
PROPERTY public final val y: kotlin.Int getter=null setter=null PROPERTY public final val y: kotlin.Int getter=null setter=null
PROPERTY public final var z: kotlin.Int getter=null setter=null PROPERTY public final var z: kotlin.Int getter=null setter=null
DUMMY ConstructorDescriptorImpl <init> FUN public constructor C()
BLOCK_BODY
CALL .<init> type=C operator=DELEGATING_CONSTRUCTOR_CALL
x: CONST Int type=kotlin.Int value='0'
y: CONST Int type=kotlin.Int value='0'
z: CONST Int type=kotlin.Int value='0'
PROPERTY public final val property: kotlin.Int = 0 getter=null setter=null PROPERTY public final val property: kotlin.Int = 0 getter=null setter=null
EXPRESSION_BODY EXPRESSION_BODY
CONST Int type=kotlin.Int value='0' CONST Int type=kotlin.Int value='0'
@@ -0,0 +1,4 @@
class C {
constructor() : this(0) {}
constructor(x: Int) {}
}
@@ -0,0 +1,9 @@
FILE /secondaryConstructors.kt
CLASS CLASS C
FUN public constructor C()
BLOCK_BODY
CALL .<init> type=C operator=DELEGATING_CONSTRUCTOR_CALL
x: CONST Int type=kotlin.Int value='0'
FUN public constructor C(/*0*/ x: kotlin.Int)
BLOCK_BODY
CALL .<init> type=kotlin.Any operator=DELEGATING_CONSTRUCTOR_CALL
@@ -48,6 +48,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/classMembers.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/classMembers.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("secondaryConstructors.kt")
public void testSecondaryConstructors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/secondaryConstructors.kt");
doTest(fileName);
}
} }
@TestMetadata("compiler/testData/ir/irText/expressions") @TestMetadata("compiler/testData/ir/irText/expressions")