Inner classes lowering.
This commit is contained in:
@@ -1261,10 +1261,13 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
ClassDescriptor captureThis = getDispatchReceiverParameterForConstructorCall(descriptor, closure);
|
||||
if (captureThis != null) {
|
||||
if (!isSynthesized && captureThis != null) {
|
||||
writeParameter(sw, JvmMethodParameterKind.OUTER, captureThis.getDefaultType(), descriptor);
|
||||
}
|
||||
|
||||
@@ -1274,12 +1277,16 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (descriptor.getKind() != CallableMemberDescriptor.Kind.SYNTHESIZED &&
|
||||
(containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY)) {
|
||||
writeParameter(
|
||||
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getStringType(), descriptor);
|
||||
writeParameter(
|
||||
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getIntType(), descriptor);
|
||||
|
||||
if (!isSynthesized) {
|
||||
if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
|
||||
writeParameter(
|
||||
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getStringType(),
|
||||
descriptor);
|
||||
writeParameter(
|
||||
sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, DescriptorUtilsKt.getBuiltIns(descriptor).getIntType(),
|
||||
descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
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.IrDeclarationOriginImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||
|
||||
interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
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_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES")
|
||||
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")
|
||||
}
|
||||
|
||||
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)
|
||||
InterfaceDelegationLowering(context.state).runOnFilePostfix(irFile)
|
||||
SharedVariablesLowering(context).runOnFilePostfix(irFile)
|
||||
InnerClassesLowering(context).runOnFilePostfix(irFile)
|
||||
InnerClassConstructorCallsLowering(context).runOnFilePostfix(irFile)
|
||||
LocalFunctionsLowering(context).runOnFilePostfix(irFile)
|
||||
EnumClassLowering(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.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -201,6 +202,9 @@ fun MemberDescriptor.calculateCommonFlags(): Int {
|
||||
else if (visibility == Visibilities.PROTECTED) {
|
||||
flags = flags.or(Opcodes.ACC_PROTECTED)
|
||||
}
|
||||
else if (visibility == JavaVisibilities.PACKAGE_VISIBILITY) {
|
||||
// default visibility
|
||||
}
|
||||
else {
|
||||
throw RuntimeException("Unsupported visibility $visibility for descriptor $this")
|
||||
}
|
||||
|
||||
+10
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -41,6 +42,15 @@ class FunctionCodegen(val irFunction: IrFunction, val classCodegen: ClassCodegen
|
||||
val descriptor = irFunction.descriptor
|
||||
|
||||
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 isStatic = isStaticMethod(classCodegen.descriptor.getMemberOwnerKind(), descriptor) || DescriptorUtils.isStaticDeclaration(descriptor)
|
||||
val frameMap = createFrameMapWithReceivers(classCodegen.state, descriptor, signature, isStatic)
|
||||
|
||||
+14
@@ -70,5 +70,19 @@ class JvmPropertyDescriptorImpl(
|
||||
containingDeclaration, null, annotations, modality, visibility, extraFlags, false, name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, source, false, false
|
||||
).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)
|
||||
}
|
||||
}
|
||||
+46
@@ -19,11 +19,14 @@ package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
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.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.util.*
|
||||
@@ -33,6 +36,8 @@ class SpecialDescriptorsFactory(
|
||||
val builtIns: KotlinBuiltIns
|
||||
) {
|
||||
private val singletonFieldDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>()
|
||||
private val outerThisDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>()
|
||||
private val innerClassConstructors = HashMap<ClassConstructorDescriptor, ClassConstructorDescriptor>()
|
||||
|
||||
fun getFieldDescriptorForEnumEntry(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor =
|
||||
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 {
|
||||
assert(enumEntryDescriptor.kind == ClassKind.ENUM_ENTRY) { "Should be enum entry: $enumEntryDescriptor" }
|
||||
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
fun PropertyDescriptorImpl.initialize(
|
||||
type: KotlinType,
|
||||
@@ -34,4 +35,14 @@ fun PropertyDescriptorImpl.initialize(
|
||||
setType(type, typeParameters, dispatchReceiverParameter, extensionReceiverParameter)
|
||||
initialize(getter, setter)
|
||||
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
|
||||
)
|
||||
|
||||
+3
-12
@@ -21,6 +21,7 @@ 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.backend.jvm.descriptors.JvmPropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
@@ -137,8 +138,8 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
val valueParameters =
|
||||
listOf(
|
||||
loweredConstructorDescriptor.createSpecialParameter(0, "name", context.builtIns.stringType),
|
||||
loweredConstructorDescriptor.createSpecialParameter(1, "ordinal", context.builtIns.intType)
|
||||
loweredConstructorDescriptor.createValueParameter(0, "name", context.builtIns.stringType),
|
||||
loweredConstructorDescriptor.createValueParameter(1, "ordinal", context.builtIns.intType)
|
||||
) +
|
||||
constructorDescriptor.valueParameters.map {
|
||||
lowerConstructorValueParameter(loweredConstructorDescriptor, it)
|
||||
@@ -152,16 +153,6 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
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(
|
||||
loweredConstructorDescriptor: ClassConstructorDescriptor,
|
||||
valueParameterDescriptor: ValueParameterDescriptor
|
||||
|
||||
+213
@@ -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
|
||||
|
||||
interface IrStatementOrigin {
|
||||
abstract class IrStatementOriginImpl(val debugName: String): IrStatementOrigin {
|
||||
override fun toString(): String = debugName
|
||||
}
|
||||
abstract class IrStatementOriginImpl(val debugName: String): IrStatementOrigin {
|
||||
override fun toString(): String = debugName
|
||||
}
|
||||
|
||||
interface IrStatementOrigin {
|
||||
object SAFE_CALL : IrStatementOriginImpl("SAFE_CALL")
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("innerClass1.kt")
|
||||
public void testInnerClass1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/innerClass1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mutable1.kt")
|
||||
public void testMutable1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion/mutable1.kt");
|
||||
|
||||
@@ -127,6 +127,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
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")
|
||||
public void testLocalClasses() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/classes/localClasses.kt");
|
||||
|
||||
Reference in New Issue
Block a user