diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index 90daa68d620..2132c168bb1 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -19,10 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFunctionLiteral -import org.jetbrains.kotlin.psi.KtLoopExpression +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import java.util.* @@ -36,38 +33,19 @@ class BodyGenerator(val scopeOwner: CallableDescriptor, override val context: Ge val irBlockBody = IrBlockBodyImpl(ktBody.startOffset, ktBody.endOffset) if (ktBody is KtBlockExpression) { - for (ktStatement in ktBody.statements) { - irBlockBody.addStatement(statementGenerator.generateStatement(ktStatement)) - } + statementGenerator.generateBlockBodyStatements(irBlockBody, ktBody) } else { - val irBodyExpression = statementGenerator.generateExpression(ktBody) - irBlockBody.addStatement(irBodyExpression.wrapWithReturn()) + statementGenerator.generateReturnExpression(ktBody, 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 = IrExpressionBodyImpl(ktInitializer.startOffset, ktInitializer.endOffset, 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 { val statementGenerator = createStatementGenerator() @@ -78,13 +56,57 @@ class BodyGenerator(val scopeOwner: CallableDescriptor, override val context: Ge irBlockBody.addStatement(statementGenerator.generateStatement(ktStatement)) } val ktReturnedValue = ktBody.statements.last() - irBlockBody.addStatement(statementGenerator.generateExpression(ktReturnedValue).wrapWithReturn()) - } - else { - irBlockBody.addStatement(statementGenerator.generateExpression(ktBody).wrapWithReturn()) + statementGenerator.generateReturnExpression(ktReturnedValue, 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] } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt index 96b0fbaf894..b99abcb639d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt @@ -31,7 +31,7 @@ class BranchingExpressionGenerator(val statementGenerator: StatementGenerator) : override val context: GeneratorContext get() = statementGenerator.context fun generateIfExpression(expression: KtIfExpression): IrExpression { - val resultType = getInferredTypeWithSmartcastsOrFail(expression) + val resultType = getInferredTypeWithImplicitCastsOrFail(expression) var ktLastIf: KtIfExpression = expression val irBranches = SmartList>() @@ -74,7 +74,7 @@ class BranchingExpressionGenerator(val statementGenerator: StatementGenerator) : scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject") } - val resultType = getInferredTypeWithSmartcastsOrFail(expression) + val resultType = getInferredTypeWithImplicitCastsOrFail(expression) val irWhen = IrWhenImpl(expression.startOffset, expression.endOffset, resultType, IrOperator.WHEN) 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 56987d44325..f3ad23625af 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 @@ -31,7 +31,7 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator val irClass = IrClassImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, IrDeclarationOrigin.DEFINED, descriptor) generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject) - generateMembersDeclaredInClassbody(irClass, ktClassOrObject) + generateMembersDeclaredInClassBody(irClass, ktClassOrObject) 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 -> for (ktDeclaration in ktClassBody.declarations) { val irMember = declarationGenerator.generateMemberDeclaration(ktDeclaration) 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 c217865c8d9..386ef7a4824 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 @@ -29,6 +29,8 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator { when (ktDeclaration) { is KtNamedFunction -> generateFunctionDeclaration(ktDeclaration) + is KtSecondaryConstructor -> + generateSecondaryConstructor(ktDeclaration) is KtProperty -> generatePropertyDeclaration(ktDeclaration) is KtClassOrObject -> @@ -56,6 +58,13 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator { 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 { val propertyDescriptor = getPropertyDescriptor(ktProperty) if (ktProperty.hasDelegate()) TODO("handle delegated property") diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt index fc8ba2704dc..dd81342d25b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt @@ -19,10 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.expressions.IrDummyExpression -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtConstantExpression -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtStringTemplateExpression +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall @@ -54,50 +51,14 @@ fun Generator.getOrFail(slice: ReadOnlySlice, key: K): V = inline fun Generator.getOrFail(slice: ReadOnlySlice, key: K, message: (K) -> String): V = context.bindingContext[slice, key] ?: throw RuntimeException(message(key)) -fun Generator.getInferredTypeWithSmartcasts(key: KtExpression): KotlinType? = +fun Generator.getInferredTypeWithImplicitCasts(key: KtExpression): KotlinType? = context.bindingContext.getType(key) -fun Generator.getInferredTypeWithSmartcastsOrFail(key: KtExpression): KotlinType = - getInferredTypeWithSmartcasts(key) ?: throw AssertionError("No type for expression: ${key.text}") +fun Generator.getInferredTypeWithImplicitCastsOrFail(key: KtExpression): KotlinType = + getInferredTypeWithImplicitCasts(key) ?: throw AssertionError("No type for expression: ${key.text}") -fun Generator.getResolvedCall(key: KtExpression): ResolvedCall? = +fun Generator.getResolvedCall(key: KtElement): ResolvedCall? = 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 = - IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithSmartcastsOrFail(ktExpression), description) \ No newline at end of file + IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, getInferredTypeWithImplicitCastsOrFail(ktExpression), description) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt index 67051e76546..a3235cc7f24 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt @@ -35,7 +35,7 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener fun generateLambda(ktLambda: KtLambdaExpression): IrStatement { val ktFun = ktLambda.functionLiteral - val lambdaExpressionType = getInferredTypeWithSmartcastsOrFail(ktLambda) + val lambdaExpressionType = getInferredTypeWithImplicitCastsOrFail(ktLambda) val lambdaDescriptor = getOrFail(BindingContext.FUNCTION, ktFun) val irBlock = IrBlockImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType, IrOperator.LAMBDA) @@ -54,7 +54,7 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener } else { // anonymous function expression - val funExpressionType = getInferredTypeWithSmartcastsOrFail(ktFun) + val funExpressionType = getInferredTypeWithImplicitCastsOrFail(ktFun) val irBlock = IrBlockImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType, IrOperator.ANONYMOUS_FUNCTION) val irFun = generateFunctionDeclaration(ktFun) 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 90626905efc..141679946ad 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 @@ -109,7 +109,7 @@ class StatementGenerator( 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") - val returnType = getInferredTypeWithSmartcasts(expression) ?: context.builtIns.unitType + val returnType = getInferredTypeWithImplicitCasts(expression) ?: context.builtIns.unitType val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, returnType) expression.statements.forEach { @@ -151,7 +151,7 @@ class StatementGenerator( override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression { val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext) ?: error("KtConstantExpression was not evaluated: ${expression.text}") - val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithSmartcastsOrFail(expression)) + val constantValue = compileTimeConstant.toConstantValue(getInferredTypeWithImplicitCastsOrFail(expression)) val constantType = constantValue.type return when (constantValue) { @@ -179,12 +179,12 @@ class StatementGenerator( } entries.size == 0 -> { return IrConstImpl.string(expression.startOffset, expression.endOffset, - getInferredTypeWithSmartcastsOrFail(expression), "") + getInferredTypeWithImplicitCastsOrFail(expression), "") } } val irStringTemplate = IrStringConcatenationImpl(expression.startOffset, expression.endOffset, - getInferredTypeWithSmartcastsOrFail(expression)) + getInferredTypeWithImplicitCastsOrFail(expression)) entries.forEach { it.expression!!.let { irStringTemplate.addArgument(it.genExpr()) } } return irStringTemplate } @@ -229,7 +229,7 @@ class StatementGenerator( IrGetVariableImpl(expression.startOffset, expression.endOffset, descriptor) else -> IrDummyExpression( - expression.startOffset, expression.endOffset, getInferredTypeWithSmartcastsOrFail(expression), + expression.startOffset, expression.endOffset, getInferredTypeWithImplicitCastsOrFail(expression), expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}" ) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt index 95b7a840dee..53410a0a1ef 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt @@ -28,7 +28,7 @@ class TryCatchExpressionGenerator(val statementGenerator: StatementGenerator) : override val context: GeneratorContext get() = statementGenerator.context fun generateTryCatch(ktTry: KtTryExpression): IrExpression { - val resultType = getInferredTypeWithSmartcastsOrFail(ktTry) + val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry) val irTryCatch = IrTryCatchImpl(ktTry.startOffset, ktTry.endOffset, resultType) irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index 5328e028420..c786f16d667 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -88,6 +88,8 @@ interface IrOperator { object LAMBDA : IrOperatorImpl("LAMBDA") 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") { companion object { private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) } diff --git a/compiler/testData/ir/irText/classes/classMembers.txt b/compiler/testData/ir/irText/classes/classMembers.txt index b757c93332c..f8a028320d7 100644 --- a/compiler/testData/ir/irText/classes/classMembers.txt +++ b/compiler/testData/ir/irText/classes/classMembers.txt @@ -2,7 +2,12 @@ FILE /classMembers.kt CLASS CLASS C PROPERTY public final val y: kotlin.Int getter=null setter=null PROPERTY public final var z: kotlin.Int getter=null setter=null - DUMMY ConstructorDescriptorImpl + FUN public constructor C() + BLOCK_BODY + CALL . 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 EXPRESSION_BODY CONST Int type=kotlin.Int value='0' diff --git a/compiler/testData/ir/irText/classes/secondaryConstructors.kt b/compiler/testData/ir/irText/classes/secondaryConstructors.kt new file mode 100644 index 00000000000..3e1c2c51c14 --- /dev/null +++ b/compiler/testData/ir/irText/classes/secondaryConstructors.kt @@ -0,0 +1,4 @@ +class C { + constructor() : this(0) {} + constructor(x: Int) {} +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/secondaryConstructors.txt b/compiler/testData/ir/irText/classes/secondaryConstructors.txt new file mode 100644 index 00000000000..ab33a4a71bb --- /dev/null +++ b/compiler/testData/ir/irText/classes/secondaryConstructors.txt @@ -0,0 +1,9 @@ +FILE /secondaryConstructors.kt + CLASS CLASS C + FUN public constructor C() + BLOCK_BODY + CALL . 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 . type=kotlin.Any operator=DELEGATING_CONSTRUCTOR_CALL diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index b4f8aacfbfa..822647c1418 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -48,6 +48,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/classMembers.kt"); 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")