Inner classes lowering.

This commit is contained in:
Dmitry Petrov
2016-10-18 15:59:33 +03:00
parent f933cf5395
commit 7dce1f438f
16 changed files with 380 additions and 31 deletions
@@ -1261,10 +1261,13 @@ public class KotlinTypeMapper {
} }
private void writeAdditionalConstructorParameters(@NotNull ClassConstructorDescriptor descriptor, @NotNull JvmSignatureWriter sw) { private void writeAdditionalConstructorParameters(@NotNull ClassConstructorDescriptor descriptor, @NotNull JvmSignatureWriter sw) {
boolean isSynthesized = descriptor.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED;
//if (isSynthesized) return;
MutableClosure closure = bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration()); MutableClosure closure = bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration());
ClassDescriptor captureThis = getDispatchReceiverParameterForConstructorCall(descriptor, closure); ClassDescriptor captureThis = getDispatchReceiverParameterForConstructorCall(descriptor, closure);
if (captureThis != null) { if (!isSynthesized && captureThis != null) {
writeParameter(sw, JvmMethodParameterKind.OUTER, captureThis.getDefaultType(), descriptor); writeParameter(sw, JvmMethodParameterKind.OUTER, captureThis.getDefaultType(), descriptor);
} }
@@ -1274,12 +1277,16 @@ public class KotlinTypeMapper {
} }
ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration(); ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (descriptor.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED &&
(containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY)) { if (!isSynthesized) {
writeParameter( if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getStringType(), descriptor); writeParameter(
writeParameter( sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getStringType(),
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getIntType(), descriptor); descriptor);
writeParameter(
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getIntType(),
descriptor);
}
} }
if (closure == null) return; if (closure == null) return;
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
@@ -26,10 +27,10 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY") object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY")
object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES") object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES")
object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE") object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE")
object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR") object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR")
} }
interface JvmLoweredStatementOrigin : IrStatementOrigin { interface JvmLoweredStatementOrigin : IrStatementOrigin {
object DEFAULT_IMPLS_DELEGATION : IrStatementOrigin.IrStatementOriginImpl("DEFAULT_IMPL_DELEGATION") object DEFAULT_IMPLS_DELEGATION : IrStatementOriginImpl("DEFAULT_IMPL_DELEGATION")
} }
@@ -35,6 +35,8 @@ class JvmLower(val context: JvmBackendContext) {
InterfaceLowering(context.state).runOnFilePostfix(irFile) InterfaceLowering(context.state).runOnFilePostfix(irFile)
InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile) InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile)
SharedVariablesLowering(context).runOnFilePostfix(irFile) SharedVariablesLowering(context).runOnFilePostfix(irFile)
InnerClassesLowering(context).runOnFilePostfix(irFile)
InnerClassConstructorCallsLowering(context).runOnFilePostfix(irFile)
LocalFunctionsLowering(context).runOnFilePostfix(irFile) LocalFunctionsLowering(context).runOnFilePostfix(irFile)
EnumClassLowering(context).runOnFilePostfix(irFile) EnumClassLowering(context).runOnFilePostfix(irFile)
ObjectClassLowering(context).runOnFilePostfix(irFile) ObjectClassLowering(context).runOnFilePostfix(irFile)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.codegen.MemberCodegen.badDescriptor
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -201,6 +202,9 @@ fun MemberDescriptor.calculateCommonFlags(): Int {
else if (visibility == Visibilities.PROTECTED) { else if (visibility == Visibilities.PROTECTED) {
flags = flags.or(Opcodes.ACC_PROTECTED) flags = flags.or(Opcodes.ACC_PROTECTED)
} }
else if (visibility == JavaVisibilities.PACKAGE_VISIBILITY) {
// default visibility
}
else { else {
throw RuntimeException("Unsupported visibility $visibility for descriptor $this") throw RuntimeException("Unsupported visibility $visibility for descriptor $this")
} }
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
@@ -41,6 +42,15 @@ class FunctionCodegen(val irFunction: IrFunction, val classCodegen: ClassCodegen
val descriptor = irFunction.descriptor val descriptor = irFunction.descriptor
fun generate() { fun generate() {
try {
doGenerate()
}
catch (e: Throwable) {
throw RuntimeException("${e.message} + while generating code for:\n${irFunction.dump()}", e)
}
}
private fun doGenerate() {
val signature = classCodegen.typeMapper.mapSignatureWithGeneric(descriptor, OwnerKind.IMPLEMENTATION) val signature = classCodegen.typeMapper.mapSignatureWithGeneric(descriptor, OwnerKind.IMPLEMENTATION)
val isStatic = isStaticMethod(classCodegen.descriptor.getMemberOwnerKind(), descriptor) || DescriptorUtils.isStaticDeclaration(descriptor) val isStatic = isStaticMethod(classCodegen.descriptor.getMemberOwnerKind(), descriptor) || DescriptorUtils.isStaticDeclaration(descriptor)
val frameMap = createFrameMapWithReceivers(classCodegen.state, descriptor, signature, isStatic) val frameMap = createFrameMapWithReceivers(classCodegen.state, descriptor, signature, isStatic)
@@ -70,5 +70,19 @@ class JvmPropertyDescriptorImpl(
containingDeclaration, null, annotations, modality, visibility, extraFlags, false, name, containingDeclaration, null, annotations, modality, visibility, extraFlags, false, name,
CallableMemberDescriptor.Kind.SYNTHESIZED, source, false, false CallableMemberDescriptor.Kind.SYNTHESIZED, source, false, false
).initialize(type) ).initialize(type)
fun createFinalField(
name: Name,
type: KotlinType,
classDescriptor: ClassDescriptor,
annotations: Annotations,
visibility: Visibility,
extraFlags: Int,
source: SourceElement
): PropertyDescriptorImpl =
JvmPropertyDescriptorImpl(
classDescriptor, null, annotations, Modality.FINAL, visibility, extraFlags, false, name,
CallableMemberDescriptor.Kind.SYNTHESIZED, source, false, false
).initialize(type, dispatchReceiverParameter = classDescriptor.thisAsReceiverParameter)
} }
} }
@@ -19,11 +19,14 @@ package org.jetbrains.kotlin.backend.jvm.descriptors
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import java.util.* import java.util.*
@@ -33,6 +36,8 @@ class SpecialDescriptorsFactory(
val builtIns: KotlinBuiltIns val builtIns: KotlinBuiltIns
) { ) {
private val singletonFieldDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>() private val singletonFieldDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>()
private val outerThisDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>()
private val innerClassConstructors = HashMap<ClassConstructorDescriptor, ClassConstructorDescriptor>()
fun getFieldDescriptorForEnumEntry(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor = fun getFieldDescriptorForEnumEntry(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor =
singletonFieldDescriptors.getOrPut(enumEntryDescriptor) { singletonFieldDescriptors.getOrPut(enumEntryDescriptor) {
@@ -52,6 +57,47 @@ class SpecialDescriptorsFactory(
) )
} }
fun getOuterThisFieldDescriptor(innerClassDescriptor: ClassDescriptor): PropertyDescriptor =
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor")
else outerThisDescriptors.getOrPut(innerClassDescriptor) {
val outerClassDescriptor = DescriptorUtils.getContainingClass(innerClassDescriptor) ?:
throw AssertionError("No containing class for inner class $innerClassDescriptor")
JvmPropertyDescriptorImpl.createFinalField(
Name.identifier("this$0"), outerClassDescriptor.defaultType, innerClassDescriptor,
Annotations.EMPTY, JavaVisibilities.PACKAGE_VISIBILITY, Opcodes.ACC_SYNTHETIC, SourceElement.NO_SOURCE
)
}
fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: ClassConstructorDescriptor): ClassConstructorDescriptor {
val innerClass = innerClassConstructor.containingDeclaration
assert(innerClass.isInner) { "Class is not inner: $innerClass" }
return innerClassConstructors.getOrPut(innerClassConstructor) {
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor)
}
}
private fun createInnerClassConstructorWithOuterThisParameter(oldDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor {
val classDescriptor = oldDescriptor.containingDeclaration
val outerThisType = (classDescriptor.containingDeclaration as ClassDescriptor).defaultType
val newDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source
)
val outerThisValueParameter = newDescriptor.createValueParameter(0, "\$outer", outerThisType)
val newValueParameters =
listOf(outerThisValueParameter) +
oldDescriptor.valueParameters.map { it.copy(newDescriptor, it.name, it.index + 1) }
newDescriptor.initialize(newValueParameters, oldDescriptor.visibility)
newDescriptor.returnType = oldDescriptor.returnType
return newDescriptor
}
private fun createEnumEntryFieldDescriptor(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor { private fun createEnumEntryFieldDescriptor(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor {
assert(enumEntryDescriptor.kind == ClassKind.ENUM_ENTRY) { "Should be enum entry: $enumEntryDescriptor" } assert(enumEntryDescriptor.kind == ClassKind.ENUM_ENTRY) { "Should be enum entry: $enumEntryDescriptor" }
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.backend.jvm.descriptors package org.jetbrains.kotlin.backend.jvm.descriptors
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
fun PropertyDescriptorImpl.initialize( fun PropertyDescriptorImpl.initialize(
type: KotlinType, type: KotlinType,
@@ -35,3 +36,13 @@ fun PropertyDescriptorImpl.initialize(
initialize(getter, setter) initialize(getter, setter)
return this return this
} }
fun CallableMemberDescriptor.createValueParameter(index: Int, name: String, type: KotlinType): ValueParameterDescriptor =
ValueParameterDescriptorImpl(
this, null,
index,
Annotations.EMPTY,
Name.identifier(name),
type,
false, false, false, false, null, SourceElement.NO_SOURCE
)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
@@ -137,8 +138,8 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
val valueParameters = val valueParameters =
listOf( listOf(
loweredConstructorDescriptor.createSpecialParameter(0, "name", context.builtIns.stringType), loweredConstructorDescriptor.createValueParameter(0, "name", context.builtIns.stringType),
loweredConstructorDescriptor.createSpecialParameter(1, "ordinal", context.builtIns.intType) loweredConstructorDescriptor.createValueParameter(1, "ordinal", context.builtIns.intType)
) + ) +
constructorDescriptor.valueParameters.map { constructorDescriptor.valueParameters.map {
lowerConstructorValueParameter(loweredConstructorDescriptor, it) lowerConstructorValueParameter(loweredConstructorDescriptor, it)
@@ -152,16 +153,6 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
return loweredConstructorDescriptor return loweredConstructorDescriptor
} }
private fun ClassConstructorDescriptor.createSpecialParameter(index: Int, name: String, type: KotlinType): ValueParameterDescriptor =
ValueParameterDescriptorImpl(
this, null,
index,
Annotations.EMPTY,
Name.identifier(name),
type,
false, false, false, false, null, SourceElement.NO_SOURCE
)
private fun lowerConstructorValueParameter( private fun lowerConstructorValueParameter(
loweredConstructorDescriptor: ClassConstructorDescriptor, loweredConstructorDescriptor: ClassConstructorDescriptor,
valueParameterDescriptor: ValueParameterDescriptor valueParameterDescriptor: ValueParameterDescriptor
@@ -0,0 +1,213 @@
/*
* 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.backend.jvm.lower
import org.jetbrains.kotlin.backend.jvm.BodyLoweringPass
import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
class InnerClassesLowering(val context: JvmBackendContext) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
InnerClassTransformer(irClass).lowerInnerClass()
}
private inner class InnerClassTransformer(val irClass: IrClass) {
val classDescriptor = irClass.descriptor
private lateinit var outerThisFieldDescriptor: PropertyDescriptor
fun lowerInnerClass() {
if (!irClass.descriptor.isInner) return
createOuterThisField()
lowerConstructors()
lowerOuterThisReferences()
}
private fun createOuterThisField() {
outerThisFieldDescriptor = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(irClass.descriptor)
irClass.declarations.add(IrFieldImpl(
irClass.startOffset, irClass.endOffset,
JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS,
outerThisFieldDescriptor
))
}
private fun lowerConstructors() {
irClass.declarations.transformFlat { irMember ->
if (irMember is IrConstructor)
lowerConstructor(irMember).singletonList()
else
null
}
}
private fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
val oldDescriptor = irConstructor.descriptor
val startOffset = irConstructor.startOffset
val endOffset = irConstructor.endOffset
val newDescriptor = context.specialDescriptorsFactory.getInnerClassConstructorWithOuterThisParameter(oldDescriptor)
val outerThisValueParameter = newDescriptor.valueParameters[0]
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall }
if (instanceInitializerIndex >= 0) {
// Initializing constructor: initialize 'this.this$0' with '$outer'
blockBody.statements.add(
instanceInitializerIndex,
IrSetFieldImpl(
startOffset, endOffset, outerThisFieldDescriptor,
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
IrGetValueImpl(startOffset, endOffset, outerThisValueParameter)
)
)
}
else {
// Delegating constructor: invoke old constructor with dispatch receiver '$outer'
val delegatingConstructorCall = (blockBody.statements.find { it is IrDelegatingConstructorCall } ?:
throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
) as IrDelegatingConstructorCall
delegatingConstructorCall.dispatchReceiver = IrGetValueImpl(
delegatingConstructorCall.startOffset, delegatingConstructorCall.endOffset, outerThisValueParameter
)
}
return IrConstructorImpl(
startOffset, endOffset,
irConstructor.origin, // TODO special origin for lowered inner class constructors?
newDescriptor,
blockBody
)
}
private fun lowerOuterThisReferences() {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val implicitThisClass = expression.descriptor.getClassDescriptorForImplicitThis() ?:
return expression
if (implicitThisClass == classDescriptor) return expression
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter, origin)
var innerClass = classDescriptor
while (innerClass != implicitThisClass) {
if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion.
return expression
}
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
val outer = classDescriptor.containingDeclaration
innerClass = outer as? ClassDescriptor ?:
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
}
return irThis
}
})
}
private fun ValueDescriptor.getClassDescriptorForImplicitThis(): ClassDescriptor? {
if (this is ReceiverParameterDescriptor) {
val receiverValue = value
if (receiverValue is ImplicitClassReceiver) {
return receiverValue.classDescriptor
}
}
return null
}
}
}
class InnerClassConstructorCallsLowering(val context: JvmBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody) {
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val dispatchReceiver = expression.dispatchReceiver ?: return expression
val callee = expression.descriptor as? ClassConstructorDescriptor ?: return expression
if (!callee.constructedClass.isInner) return expression
val newCallee = context.specialDescriptorsFactory.getInnerClassConstructorWithOuterThisParameter(callee)
val newCall = IrCallImpl(
expression.startOffset, expression.endOffset, newCallee,
null, // TODO type arguments map
expression.origin
)
newCall.putValueArgument(0, dispatchReceiver)
for (i in 1 .. newCallee.valueParameters.lastIndex) {
newCall.putValueArgument(i, expression.getValueArgument(i))
}
return newCall
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val dispatchReceiver = expression.dispatchReceiver ?: return expression
val callee = expression.descriptor
if (!callee.constructedClass.isInner) return expression
val newCallee = context.specialDescriptorsFactory.getInnerClassConstructorWithOuterThisParameter(callee)
val newCall = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset, newCallee,
null // TODO type arguments map
)
newCall.putValueArgument(0, dispatchReceiver)
for (i in 1 .. newCallee.valueParameters.lastIndex) {
newCall.putValueArgument(i, expression.getValueArgument(i))
}
return newCall
}
// TODO callable references?
})
}
}
@@ -16,11 +16,11 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
interface IrStatementOrigin { abstract class IrStatementOriginImpl(val debugName: String): IrStatementOrigin {
abstract class IrStatementOriginImpl(val debugName: String): IrStatementOrigin { override fun toString(): String = debugName
override fun toString(): String = debugName }
}
interface IrStatementOrigin {
object SAFE_CALL : IrStatementOriginImpl("SAFE_CALL") object SAFE_CALL : IrStatementOriginImpl("SAFE_CALL")
object UMINUS : IrStatementOriginImpl("UMINUS") object UMINUS : IrStatementOriginImpl("UMINUS")
@@ -0,0 +1,8 @@
class Outer {
val x = "O"
inner class Inner {
val y = x + "K"
}
}
fun box() = Outer().Inner().y
@@ -0,0 +1,5 @@
class Outer {
inner class Inner(val x: Int) {
constructor() : this(0)
}
}
@@ -0,0 +1,25 @@
FILE /innerClassWithDelegatingConstructor.kt
CLASS CLASS Outer
CONSTRUCTOR public constructor Outer()
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
INSTANCE_INITIALIZER_CALL classDescriptor='Outer'
CLASS CLASS Inner
CONSTRUCTOR public constructor Inner(x: kotlin.Int)
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
INSTANCE_INITIALIZER_CALL classDescriptor='Inner'
PROPERTY public final val x: kotlin.Int
FIELD PROPERTY_BACKING_FIELD public final val x: kotlin.Int
EXPRESSION_BODY
GET_VAR 'value-parameter x: Int' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-x>(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-x>(): Int'
GET_FIELD 'x: Int' type=kotlin.Int origin=null
receiver: GET_VAR '<receiver: Inner>' type=Outer.Inner origin=null
CONSTRUCTOR public constructor Inner()
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Inner(Int)'
$this: GET_VAR '<receiver: Outer>' type=Outer origin=null
x: CONST Int type=kotlin.Int value='0'
@@ -109,6 +109,12 @@ public class IrOnlyBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTest
doTest(fileName); doTest(fileName);
} }
@TestMetadata("innerClass1.kt")
public void testInnerClass1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/innerClass1.kt");
doTest(fileName);
}
@TestMetadata("mutable1.kt") @TestMetadata("mutable1.kt")
public void testMutable1() throws Exception { public void testMutable1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/mutable1.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/mutable1.kt");
@@ -127,6 +127,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("innerClassWithDelegatingConstructor.kt")
public void testInnerClassWithDelegatingConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/innerClassWithDelegatingConstructor.kt");
doTest(fileName);
}
@TestMetadata("localClasses.kt") @TestMetadata("localClasses.kt")
public void testLocalClasses() throws Exception { public void testLocalClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/localClasses.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/localClasses.kt");