diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/WrappedDescriptors.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/WrappedDescriptors.kt index 78ceda5fcc5..147847dbf7e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/WrappedDescriptors.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/WrappedDescriptors.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.types.toKotlinType +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -200,6 +201,7 @@ open class WrappedVariableDescriptor( override fun getContainingDeclaration() = (owner.parent as IrFunction).descriptor override fun getType() = owner.type.toKotlinType() + override fun getReturnType() = getType() override fun getName() = owner.name override fun isConst() = owner.isConst override fun isVar() = owner.isVar @@ -489,7 +491,7 @@ open class WrappedPropertyDescriptor( annotations: Annotations = Annotations.EMPTY, private val sourceElement: SourceElement = SourceElement.NO_SOURCE ) : PropertyDescriptor, WrappedDeclarationDescriptor(annotations) { - override fun getModality() = if (owner.isFinal) Modality.FINAL else Modality.OPEN + override fun getModality() = owner.correspondingProperty?.modality ?: Modality.FINAL override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection) { TODO("not implemented") @@ -553,21 +555,18 @@ open class WrappedPropertyDescriptor( override fun getType(): KotlinType = owner.type.toKotlinType() - override fun isVar() = owner.isFinal + override fun isVar() = !owner.isFinal - override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? { - TODO("not implemented") - } + override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = + if (owner.isStatic) null else (owner.parentAsClass.thisReceiver?.descriptor as ReceiverParameterDescriptor) override fun isConst() = false override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor - override fun isLateInit() = false + override fun isLateInit() = owner.correspondingProperty?.isLateinit ?: false - override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? { - TODO("not implemented") - } + override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = owner.correspondingProperty?.descriptor?.extensionReceiverParameter override fun isExternal() = owner.isExternal diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 72bf49fe4de..80abbb1606e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name import java.io.StringWriter @@ -303,3 +304,21 @@ fun IrType.remapTypeParameters(source: IrTypeParametersContainer, target: IrType else -> this } +/* Copied from K/N */ +fun IrDeclarationContainer.addChild(declaration: IrDeclaration) { + this.declarations += declaration + declaration.accept(SetDeclarationsParentVisitor, this) +} + +object SetDeclarationsParentVisitor : IrElementVisitor { + override fun visitElement(element: IrElement, data: IrDeclarationParent) { + if (element !is IrDeclarationParent) { + element.acceptChildren(this, data) + } + } + + override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) { + declaration.parent = data + super.visitDeclaration(declaration, data) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index d6e028c3414..92ee7eb0157 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -7,34 +7,29 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.expressions.IrBlock -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import java.util.* +object SYNTHESIZED_INIT_BLOCK: IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK") class InitializersLowering( val context: CommonBackendContext, @@ -42,83 +37,101 @@ class InitializersLowering( private val clinitNeeded: Boolean ) : ClassLoweringPass { override fun lower(irClass: IrClass) { - val classInitializersBuilder = ClassInitializersBuilder(irClass) - irClass.acceptChildrenVoid(classInitializersBuilder) + val instanceInitializerStatements = handleNonStatics(irClass) + transformInstanceInitializerCallsInConstructors(irClass, instanceInitializerStatements) - classInitializersBuilder.transformInstanceInitializerCallsInConstructors(irClass) - - if (clinitNeeded && classInitializersBuilder.staticInitializerStatements.isNotEmpty()) - classInitializersBuilder.createStaticInitializationMethod(irClass) + val staticInitializerStatements = handleStatics(irClass) + if (clinitNeeded && staticInitializerStatements.isNotEmpty()) + createStaticInitializationMethod(irClass, staticInitializerStatements) } - private inner class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid { - val staticInitializerStatements = ArrayList() + fun handleNonStatics(irClass: IrClass) = + irClass.declarations.filter { + (it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic) + }.mapNotNull { handleDeclaration(irClass, it) } - val instanceInitializerStatements = ArrayList() + fun handleStatics(irClass: IrClass) = + // Hardcoded order of initializers + (irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY } + + irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES } + + irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE } + + irClass.declarations.filter { + (it is IrField && it.isStatic && it.origin !in listOf( + IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY, + IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES, + IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE + )) || (it is IrAnonymousInitializer && it.isStatic) + }) + .mapNotNull { handleDeclaration(irClass, it) } - override fun visitElement(element: IrElement) { - // skip everything else - } + fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when(declaration) { + is IrField -> handleField(irClass, declaration) + is IrAnonymousInitializer -> handleAnonymousInitializer(declaration) + else -> null + } - override fun visitField(declaration: IrField) { - val irFieldInitializer = declaration.initializer?.expression ?: return + fun handleField(irClass: IrClass, declaration: IrField): IrStatement? { + val irFieldInitializer = declaration.initializer?.expression ?: return null - val receiver = - if (!declaration.isStatic) // TODO isStaticField - IrGetValueImpl( - irFieldInitializer.startOffset, irFieldInitializer.endOffset, - irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol - ) - else null - val irSetField = IrSetFieldImpl( - irFieldInitializer.startOffset, irFieldInitializer.endOffset, - declaration.symbol, - receiver, - irFieldInitializer, - context.irBuiltIns.unitType, - null, null - ) - - if (declaration.isStatic) { - staticInitializerStatements.add(irSetField) - } else { - instanceInitializerStatements.add(irSetField) - } - } - - override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) { - instanceInitializerStatements.addAll(declaration.body.statements) - } - - fun transformInstanceInitializerCallsInConstructors(irClass: IrClass) { - irClass.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression { - val copiedBlock = IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements).copy(irClass) as IrBlock - return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements) - } - }) - } - - fun createStaticInitializationMethod(irClass: IrClass) { - val staticInitializerDescriptor = SimpleFunctionDescriptorImpl.create( - irClass.descriptor, Annotations.EMPTY, clinitName, - CallableMemberDescriptor.Kind.SYNTHESIZED, - SourceElement.NO_SOURCE - ) - staticInitializerDescriptor.initialize( - null, null, emptyList(), emptyList(), - irClass.descriptor.builtIns.unitType, - Modality.FINAL, Visibilities.PUBLIC - ) - irClass.declarations.add( - IrFunctionImpl( - irClass.startOffset, irClass.endOffset, declarationOrigin, - staticInitializerDescriptor, - IrBlockBodyImpl(irClass.startOffset, irClass.endOffset, - staticInitializerStatements.map { it.copy(irClass) }) + val receiver = + if (!declaration.isStatic) // TODO isStaticField + IrGetValueImpl( + irFieldInitializer.startOffset, irFieldInitializer.endOffset, + irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol ) - ) - } + else null + return IrSetFieldImpl( + irFieldInitializer.startOffset, irFieldInitializer.endOffset, + declaration.symbol, + receiver, + irFieldInitializer, + context.irBuiltIns.unitType, + null, null + ) + } + + + fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = IrBlockImpl( + declaration.startOffset, declaration.endOffset, + context.irBuiltIns.unitType, + SYNTHESIZED_INIT_BLOCK, + declaration.body.statements + ) + + fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List) { + irClass.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression { + val copiedBlock = + IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements).copy( + irClass + ) as IrBlock + return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements) + } + }) + } + + fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List) { + val staticInitializerDescriptor = SimpleFunctionDescriptorImpl.create( + irClass.descriptor, Annotations.EMPTY, clinitName, + CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE + ) + staticInitializerDescriptor.initialize( + null, null, emptyList(), emptyList(), + irClass.descriptor.builtIns.unitType, + Modality.FINAL, Visibilities.PUBLIC + ) + irClass.declarations.add( + IrFunctionImpl( + irClass.startOffset, irClass.endOffset, declarationOrigin, + staticInitializerDescriptor, + IrBlockBodyImpl(irClass.startOffset, irClass.endOffset, + staticInitializerStatements.map { it.copy(irClass) }) + ).apply { + returnType = context.irBuiltIns.unitType + accept(SetDeclarationsParentVisitor, this) + } + ) } companion object { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt index 4a3373d645c..07ccf7f6285 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BackendContext +import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl @@ -33,6 +34,8 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classifierOrFail +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid @@ -235,3 +238,30 @@ fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index ) else -> throw Error("Unexpected parameter descriptor: $this") } + +fun IrBody.replaceThisByStaticReference( + context: CommonBackendContext, + irClass: IrClass, + oldThisReceiverParameter: IrValueParameter +): IrBody = + transform(ReplaceThisByStaticReference(context, irClass, oldThisReceiverParameter), null) + +private class ReplaceThisByStaticReference( + val context: CommonBackendContext, + val irClass: IrClass, + val oldThisReceiverParameter: IrValueParameter +) : IrElementTransformer { + override fun visitGetValue(expression: IrGetValue, data: Nothing?): IrExpression { + val irGetValue = expression + if (irGetValue.symbol == oldThisReceiverParameter.symbol) { + val instanceField = context.declarationFactory.getFieldForObjectInstance(irClass) + return IrGetFieldImpl( + expression.startOffset, + expression.endOffset, + instanceField.symbol, + irClass.defaultType + ) + } + return super.visitGetValue(irGetValue, data) + } +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt index ee87c4becb6..93d16809a83 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/PropertiesLowering.kt @@ -36,7 +36,8 @@ class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass { private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List? = if (declaration is IrProperty) ArrayList(3).apply { - if (kind != ClassKind.ANNOTATION_CLASS) { + // JvmFields in a companion object refer to companion's owners and should not be generated within companion. + if (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent) { addIfNotNull(declaration.backingField) } addIfNotNull(declaration.getter) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index db42eb419f7..01e16efcd73 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -24,9 +24,6 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPL") - 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") object TO_ARRAY : IrDeclarationOriginImpl("TO_ARRAY") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 5466855ed81..1165e3b95b1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -40,6 +40,7 @@ class JvmLower(val context: JvmBackendContext) { LateinitLowering(context, true).lower(irFile) + MoveCompanionObjectFieldsLowering(context).runOnFilePostfix(irFile) ConstAndJvmFieldPropertiesLowering(context).lower(irFile) PropertiesLowering().lower(irFile) AnnotationLowering().runOnFilePostfix(irFile) //should be run before defaults lowering diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 45f7c361b12..ba3838e889c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDescriptorWithExtraFlags import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding @@ -159,7 +158,7 @@ open class ClassCodegen protected constructor( fieldSignature, null/*TODO support default values*/ ) - if (field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) { + if (field.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) { AnnotationCodegen.forField(fv, this, typeMapper).genAnnotations(field.descriptor, null) } else { @@ -254,7 +253,12 @@ fun MemberDescriptor.calculateCommonFlags(): Int { private fun MemberDescriptor.calcModalityFlag(): Int { var flags = 0 - when (effectiveModality) { + if (this is PropertyDescriptor) { + // Modality for a field: set FINAL for vals + if (!isVar && !isLateInit) { + flags = flags.or(Opcodes.ACC_FINAL) + } + } else when (effectiveModality) { Modality.ABSTRACT -> { flags = flags.or(Opcodes.ACC_ABSTRACT) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt index 4cd913a034f..0d95cc13445 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt @@ -61,7 +61,7 @@ class JvmDeclarationFactory( IrFieldImpl( enumEntry.startOffset, enumEntry.endOffset, - JvmLoweredDeclarationOrigin.FIELD_FOR_ENUM_ENTRY, + IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY, symbol, type ) @@ -181,7 +181,7 @@ class JvmDeclarationFactory( return IrFieldImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - JvmLoweredDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE, + IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE, symbol, singleton.defaultType ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstAndJvmFieldPropertiesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstAndJvmFieldPropertiesLowering.kt index dd3ec5268ef..ee88e091831 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstAndJvmFieldPropertiesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstAndJvmFieldPropertiesLowering.kt @@ -5,30 +5,23 @@ package org.jetbrains.kotlin.backend.jvm.lower +import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.codegen.JvmCodegenUtil -import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor -import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetterCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor -class ConstAndJvmFieldPropertiesLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { - +class ConstAndJvmFieldPropertiesLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(this) } @@ -43,7 +36,8 @@ class ConstAndJvmFieldPropertiesLowering(val context: JvmBackendContext) : IrEle } override fun visitCall(expression: IrCall): IrExpression { - val irProperty = (expression.symbol.owner as? IrSimpleFunction)?.correspondingProperty ?: return super.visitCall(expression) + val irSimpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression) + val irProperty = irSimpleFunction.correspondingProperty ?: return super.visitCall(expression) if (irProperty.isConst) { (irProperty.backingField?.initializer?.expression as? IrConst<*>)?.let { return it } @@ -63,28 +57,60 @@ class ConstAndJvmFieldPropertiesLowering(val context: JvmBackendContext) : IrEle return super.visitCall(expression) } - private fun substituteSetter(irProperty: IrProperty, expression: IrCall): IrSetFieldImpl { - return IrSetFieldImpl( + private fun substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression { + val backingField = irProperty.backingField!! + val receiver = expression.dispatchReceiver?.let { super.visitExpression(it) } + val setExpr = IrSetFieldImpl( expression.startOffset, expression.endOffset, - irProperty.backingField!!.symbol, - expression.dispatchReceiver, - expression.getValueArgument(expression.symbol.owner.valueParameters.lastIndex)!!, + backingField.symbol, + receiver, + super.visitExpression(expression.getValueArgument(expression.valueArgumentsCount - 1)!!), expression.type, expression.origin, - expression.superQualifier?.let { context.ir.symbols.externalSymbolTable.referenceClass(it) } + expression.superQualifierSymbol ) + return buildSubstitution(backingField.isStaticField(), setExpr, receiver) } private fun substituteGetter(irProperty: IrProperty, expression: IrCall): IrExpression { - return IrGetFieldImpl( + val backingField = irProperty.backingField!! + val receiver = expression.dispatchReceiver?.let { super.visitExpression(it) } + val getExpr = IrGetFieldImpl( expression.startOffset, expression.endOffset, - irProperty.backingField!!.symbol, + backingField.symbol, expression.type, - expression.dispatchReceiver, + receiver, expression.origin, - expression.superQualifier?.let { context.ir.symbols.externalSymbolTable.referenceClass(it) } + expression.superQualifierSymbol ) + return buildSubstitution(backingField.isStaticField(), getExpr, receiver) + } + + private fun buildSubstitution(needBlock: Boolean, setOrGetExpr: IrFieldAccessExpression, receiver: IrExpression?): IrExpression { + if (receiver != null && needBlock) { + // Evaluate `dispatchReceiver` for the sake of its side effects, then return `setOrGetExpr`. + return context.createIrBuilder(setOrGetExpr.symbol, setOrGetExpr.startOffset, setOrGetExpr.endOffset).irBlock(setOrGetExpr) { + // `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here + val receiverVoid = IrTypeOperatorCallImpl( + receiver.startOffset, receiver.endOffset, + context.irBuiltIns.unitType, + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, + context.irBuiltIns.unitType, context.irBuiltIns.unitType.classifierOrFail, + receiver + ) + + +receiverVoid + setOrGetExpr.receiver = null + +setOrGetExpr + } + } else { + // Just `setOrGetExpr` (`dispatchReceiver` is evaluated as a subexpression thereof) + return setOrGetExpr + } } } + +// Should probably be an utility function with a more direct implementation. +private fun IrField.isStaticField() = (descriptor.dispatchReceiverParameter == null) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt index 8cd3bf2fca2..69d5eb48947 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.jvm.lower import gnu.trove.TObjectIntHashMap import org.jetbrains.kotlin.backend.common.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.* @@ -221,7 +220,7 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass { val irValuesInitializer = createSyntheticValuesFieldInitializerExpression() return IrFieldImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.FIELD_FOR_ENUM_VALUES, + UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES, createSyntheticValuesFieldDescriptor(valuesArrayType), valuesArrayType.toIrType()!!, IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irValuesInitializer) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt index 5e7076bc642..a9ca4e3f92b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock +import org.jetbrains.kotlin.backend.common.lower.replaceThisByStaticReference import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin @@ -156,26 +157,7 @@ private class SingletonObjectJvmStaticLowering( } fun modifyBody(irFunction: IrFunction, irClass: IrClass, oldDispatchReceiverParameter: IrValueParameter) { - irFunction.body = irFunction.body?.transform(ReplaceThisByStaticReference(context, irClass, oldDispatchReceiverParameter), null) - } -} - -private class ReplaceThisByStaticReference( - val context: JvmBackendContext, - val irClass: IrClass, - val oldThisReceiverParameter: IrValueParameter -) : IrElementTransformer { - override fun visitGetValue(expression: IrGetValue, data: Nothing?): IrExpression { - if (expression.symbol == oldThisReceiverParameter.symbol) { - val instanceField = context.declarationFactory.getFieldForObjectInstance(irClass) - return IrGetFieldImpl( - expression.startOffset, - expression.endOffset, - instanceField.symbol, - irClass.defaultType - ) - } - return super.visitGetValue(expression, data) + irFunction.body = irFunction.body?.replaceThisByStaticReference(context, irClass, oldDispatchReceiverParameter) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt new file mode 100644 index 00000000000..db4b6985aa9 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt @@ -0,0 +1,226 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor +import org.jetbrains.kotlin.backend.common.lower.replaceThisByStaticReference +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.ir.util.isObject +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.name.Name + +class MoveCompanionObjectFieldsLowering(val context: CommonBackendContext) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + val fieldReplacementMap = mutableMapOf() + if (irClass.isObject && !irClass.isCompanion && irClass.visibility != Visibilities.LOCAL) { + handleObject(irClass, fieldReplacementMap) + } else { + handleClass(irClass, fieldReplacementMap) + } + irClass.replaceFieldReferences(fieldReplacementMap) + } + + private fun handleObject(irObject: IrClass, fieldReplacementMap: MutableMap) { + irObject.declarations.replaceAll { + when (it) { + is IrProperty -> { + // The field is not actually moved, just replaced by a static field + movePropertyFieldToStaticParent(it, irObject, irObject, fieldReplacementMap) + it + } + is IrAnonymousInitializer -> moveAnonymousInitializerToStaticParent(it, irObject, irObject) + else -> it + } + } + } + + private fun handleClass(irClass: IrClass, fieldReplacementMap: MutableMap) { + val companion = irClass.declarations.find { + it is IrClass && it.isCompanion + } as IrClass? ?: return + if (irClass.isInterface && !companion.allFieldsAreJvmField()) return + companion.declarations.forEach { + when (it) { + is IrProperty -> { + val newField = movePropertyFieldToStaticParent(it, companion, irClass, fieldReplacementMap) + if (newField != null) irClass.declarations.add(newField) + } + is IrAnonymousInitializer -> { + val newInitializer = moveAnonymousInitializerToStaticParent(it, companion, irClass) + irClass.declarations.add(newInitializer) + } + else -> Unit + } + } + companion.declarations.removeAll { it is IrAnonymousInitializer } + } + + private fun IrClass.allFieldsAreJvmField() = + declarations.filterIsInstance() + .mapNotNull { it.backingField }.all { it.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) } + + private fun movePropertyFieldToStaticParent( + irProperty: IrProperty, + propertyParent: IrClass, + fieldParent: IrClass, + fieldReplacementMap: MutableMap + ): IrField? { + if (irProperty.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return null + val oldField = irProperty.backingField ?: return null + val newField = createStaticBackingField(oldField, propertyParent, fieldParent) + + irProperty.backingField = newField + + fieldReplacementMap[oldField.symbol] = newField.symbol + + return newField + } + + private fun moveAnonymousInitializerToStaticParent( + oldInitializer: IrAnonymousInitializer, + oldParent: IrClass, + newParent: IrClass + ): IrAnonymousInitializer = + with(oldInitializer) { + IrAnonymousInitializerImpl( + startOffset, endOffset, origin, IrAnonymousInitializerSymbolImpl(newParent.descriptor), + isStatic = true + ).apply { + parent = newParent + body = oldInitializer.body.transferToNewParent(oldParent, newParent) + } + } + + private fun IrBlockBody.transferToNewParent(oldParent: IrClass, newParent: IrClass): IrBlockBody { + val objectInstanceField = context.declarationFactory.getFieldForObjectInstance(oldParent) + return transform( + data = null, + transformer = object : IrElementTransformerVoid() { + val variableMap = mutableMapOf() + + override fun visitVariable(declaration: IrVariable): IrStatement { + val newDescriptor = WrappedVariableDescriptor(declaration.descriptor.annotations, declaration.descriptor.source) + if (declaration.parent == oldParent) { + val newVariable = IrVariableImpl( + declaration.startOffset, declaration.endOffset, + declaration.origin, IrVariableSymbolImpl(newDescriptor), + declaration.name, declaration.type, declaration.isVar, declaration.isConst, declaration.isLateinit + ).apply { + newDescriptor.bind(this) + parent = newParent + initializer = declaration.initializer + } + variableMap[declaration] = newVariable + return super.visitVariable(newVariable) + } + return super.visitVariable(declaration) + } + + override fun visitGetValue(expression: IrGetValue): IrExpression { + if (expression.symbol.owner == oldParent.thisReceiver) { + return IrGetFieldImpl( + expression.startOffset, expression.endOffset, + objectInstanceField.symbol, + expression.type + ) + } + variableMap[expression.symbol.owner]?.let { newVariable -> + return IrGetValueImpl( + expression.startOffset, expression.endOffset, + expression.type, + newVariable.symbol, + expression.origin + ) + } + return super.visitGetValue(expression) + } + }) as IrBlockBody + } + + private fun createStaticBackingField(oldField: IrField, propertyParent: IrClass, fieldParent: IrClass): IrField { + val newName = if (fieldParent == propertyParent || + oldField.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) || + oldField.correspondingProperty?.isConst == true + ) + oldField.name + else + Name.identifier(oldField.name.toString() + "\$companion") + val descriptor = WrappedPropertyDescriptor(oldField.descriptor.annotations, oldField.descriptor.source) + val field = IrFieldImpl( + oldField.startOffset, oldField.endOffset, + IrDeclarationOrigin.PROPERTY_BACKING_FIELD, + IrFieldSymbolImpl(descriptor), + newName, oldField.type, oldField.visibility, + isFinal = oldField.isFinal, + isExternal = oldField.isExternal, + isStatic = true + ).apply { + descriptor.bind(this) + parent = fieldParent + oldField.annotations.mapTo(annotations) { it } + } + val oldInitializer = oldField.initializer + if (oldInitializer != null) { + field.initializer = oldInitializer.replaceThisByStaticReference( + context, + propertyParent, + propertyParent.thisReceiver!! + ) as IrExpressionBody + } + + return field + } +} + +private fun IrElement.replaceFieldReferences(replacementMap: Map) { + transformChildrenVoid(FieldReplacer(replacementMap)) +} + +private class FieldReplacer(val replacementMap: Map) : IrElementTransformerVoid() { + override fun visitGetField(expression: IrGetField): IrExpression = + replacementMap[expression.symbol]?.let { newSymbol -> + IrGetFieldImpl( + expression.startOffset, expression.endOffset, + newSymbol, + expression.type, + /* receiver = */ null, + expression.origin, + expression.superQualifierSymbol + ) + } ?: super.visitGetField(expression) + + override fun visitSetField(expression: IrSetField): IrExpression = + replacementMap[expression.symbol]?.let { newSymbol -> + IrSetFieldImpl( + expression.startOffset, expression.endOffset, + replacementMap[expression.symbol]!!, + /* receiver = */ null, + visitExpression(expression.value), + expression.type, + expression.origin, + expression.superQualifierSymbol + ) + } ?: super.visitSetField(expression) +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt index 34969cf81a9..a3d5d46a31e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt @@ -8,15 +8,11 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.codegen.JvmCodegenUtil.isCompanionObjectInInterfaceNotIntrinsic import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl @@ -24,7 +20,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.isObject @@ -80,7 +75,9 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer } publicInstanceField.parent = publicInstanceOwner - pendingTransformations.add { publicInstanceOwner.declarations.add(publicInstanceField) } + pendingTransformations.add { + publicInstanceOwner.declarations.add(publicInstanceField) + } } private fun createInstanceFieldWithInitializer( @@ -103,7 +100,7 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer objectType: IrType ): IrField = IrFieldImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE, + UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE, fieldSymbol, objectType ).also { it.initializer = IrExpressionBodyImpl(instanceInitializer) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrAnonymousInitializer.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrAnonymousInitializer.kt index ee74cd2209d..c07fa2cd271 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrAnonymousInitializer.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrAnonymousInitializer.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.symbols.IrAnonymousInitializerSymbol interface IrAnonymousInitializer : IrSymbolDeclaration { override val descriptor: ClassDescriptor // TODO special descriptor for anonymous initializer blocks + val isStatic: Boolean var body: IrBlockBody } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index 396c2a2726a..f8272aab781 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -38,6 +38,10 @@ interface IrDeclarationOrigin { object IR_EXTERNAL_DECLARATION_STUB : IrDeclarationOriginImpl("IR_EXTERNAL_DECLARATION_STUB") object IR_BUILTINS_STUB : IrDeclarationOriginImpl("IR_BUILTINS_STUB") object BRIDGE : IrDeclarationOriginImpl("BRIDGE") + + 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") } abstract class IrDeclarationOriginImpl(val name: String) : IrDeclarationOrigin { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrAnonymousInitializerImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrAnonymousInitializerImpl.kt index ea7fcad2f26..f14451967ae 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrAnonymousInitializerImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrAnonymousInitializerImpl.kt @@ -29,7 +29,8 @@ class IrAnonymousInitializerImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - override val symbol: IrAnonymousInitializerSymbol + override val symbol: IrAnonymousInitializerSymbol, + override val isStatic: Boolean = false ) : IrDeclarationBase(startOffset, endOffset, origin), IrAnonymousInitializer { @@ -37,17 +38,19 @@ class IrAnonymousInitializerImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - descriptor: ClassDescriptor + descriptor: ClassDescriptor, + isStatic: Boolean = false ) : - this(startOffset, endOffset, origin, IrAnonymousInitializerSymbolImpl(descriptor)) + this(startOffset, endOffset, origin, IrAnonymousInitializerSymbolImpl(descriptor), isStatic) constructor( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, descriptor: ClassDescriptor, - body: IrBlockBody - ) : this(startOffset, endOffset, origin, descriptor) { + body: IrBlockBody, + isStatic: Boolean = false + ) : this(startOffset, endOffset, origin, descriptor, isStatic) { this.body = body } diff --git a/compiler/testData/codegen/box/jvmField/initializersOrder.kt b/compiler/testData/codegen/box/jvmField/initializersOrder.kt new file mode 100644 index 00000000000..13950584c96 --- /dev/null +++ b/compiler/testData/codegen/box/jvmField/initializersOrder.kt @@ -0,0 +1,36 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME + +import kotlin.test.assertEquals + +class WithCompanion { + companion object { + var a = 0 + init { + a++ + } + @JvmField var b = a + init { + b++ + } + val c = b + } +} + +object Object { + var a = 0 + init { + a++ + } + @JvmField var b = a + init { + b++ + } + val c = b +} + +fun box(): String { + assertEquals(2, WithCompanion.c, "Field WithCompanion.c") + assertEquals(2, Object.c, "Field Object") + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/jvmField/interfaceCompanionWithJava.kt b/compiler/testData/codegen/box/jvmField/interfaceCompanionWithJava.kt index 10ce29b0739..76f63e669c4 100644 --- a/compiler/testData/codegen/box/jvmField/interfaceCompanionWithJava.kt +++ b/compiler/testData/codegen/box/jvmField/interfaceCompanionWithJava.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +JvmFieldInInterface -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/jvmField/publicFieldJava.kt b/compiler/testData/codegen/box/jvmField/publicFieldJava.kt new file mode 100644 index 00000000000..43b71c9d5bd --- /dev/null +++ b/compiler/testData/codegen/box/jvmField/publicFieldJava.kt @@ -0,0 +1,43 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME + +// FILE: Test.java + +public class Test { + public static String getField() + { + return new A().field; + } + public static String getCField() + { + return A.cfield; + } + public static String getObjectField() + { + return Object.field; + } +} + +// FILE: publicFieldJava.kt + +class A { + @JvmField public val field = "OK"; + + companion object { + @JvmField public val cfield = "OK"; + } +} + +object Object { + @JvmField public val field = "OK"; +} + + +fun box(): String { + if (Test.getField() != "OK") return "fail 1: ${Test.getField()}" + if (Test.getCField() != "OK") return "fail 2: ${Test.getCField()}" + if (Test.getObjectField() != "OK") return "fail 3: ${Test.getObjectField()}" + + return "OK" + +} diff --git a/compiler/testData/codegen/box/jvmStatic/enumCompanion.kt b/compiler/testData/codegen/box/jvmStatic/enumCompanion.kt index ee24a269ccf..ddff8ec713b 100644 --- a/compiler/testData/codegen/box/jvmStatic/enumCompanion.kt +++ b/compiler/testData/codegen/box/jvmStatic/enumCompanion.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/objects/localFunctionInObjectInitializer_kt4516.kt b/compiler/testData/codegen/box/objects/localFunctionInObjectInitializer_kt4516.kt index be7d8cdcd90..c59e782da64 100644 --- a/compiler/testData/codegen/box/objects/localFunctionInObjectInitializer_kt4516.kt +++ b/compiler/testData/codegen/box/objects/localFunctionInObjectInitializer_kt4516.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR object O { val mmmap = HashMap(); diff --git a/compiler/testData/codegen/box/objects/objectInitialization_kt5523.kt b/compiler/testData/codegen/box/objects/objectInitialization_kt5523.kt index dfc5fd020fc..3238fe1f9ce 100644 --- a/compiler/testData/codegen/box/objects/objectInitialization_kt5523.kt +++ b/compiler/testData/codegen/box/objects/objectInitialization_kt5523.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR object A { val a = "OK" val b = A.a diff --git a/compiler/testData/codegen/box/objects/privateExtensionFromInitializer_kt4543.kt b/compiler/testData/codegen/box/objects/privateExtensionFromInitializer_kt4543.kt index 653004fe6e8..ffcb2ada647 100644 --- a/compiler/testData/codegen/box/objects/privateExtensionFromInitializer_kt4543.kt +++ b/compiler/testData/codegen/box/objects/privateExtensionFromInitializer_kt4543.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR class A(val result: String) fun a(body: A.() -> String): String { diff --git a/compiler/testData/codegen/box/objects/privateFunctionFromClosureInInitializer_kt5582.kt b/compiler/testData/codegen/box/objects/privateFunctionFromClosureInInitializer_kt5582.kt index 44cdf326d85..5b71ab435fe 100644 --- a/compiler/testData/codegen/box/objects/privateFunctionFromClosureInInitializer_kt5582.kt +++ b/compiler/testData/codegen/box/objects/privateFunctionFromClosureInInitializer_kt5582.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR interface T object Foo { diff --git a/compiler/testData/codegen/box/objects/selfReferenceToCompanionObjectInInlineLambdaInConstructorBody.kt b/compiler/testData/codegen/box/objects/selfReferenceToCompanionObjectInInlineLambdaInConstructorBody.kt index 961d2bbbcdd..892e82811a1 100644 --- a/compiler/testData/codegen/box/objects/selfReferenceToCompanionObjectInInlineLambdaInConstructorBody.kt +++ b/compiler/testData/codegen/box/objects/selfReferenceToCompanionObjectInInlineLambdaInConstructorBody.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR class Test { companion object { fun ok() = "OK" diff --git a/compiler/testData/codegen/box/objects/selfReferenceToObjectInInlineLambdaInConstructorBody.kt b/compiler/testData/codegen/box/objects/selfReferenceToObjectInInlineLambdaInConstructorBody.kt index 063fa2ec8bd..88cfbb44f32 100644 --- a/compiler/testData/codegen/box/objects/selfReferenceToObjectInInlineLambdaInConstructorBody.kt +++ b/compiler/testData/codegen/box/objects/selfReferenceToObjectInInlineLambdaInConstructorBody.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR object Test { fun ok() = "OK" val x = run { Test.ok() } diff --git a/compiler/testData/codegen/box/properties/classFieldInsideLocalInSetter.kt b/compiler/testData/codegen/box/properties/classFieldInsideLocalInSetter.kt index e5446f5a1bc..e6e1c9f17f4 100644 --- a/compiler/testData/codegen/box/properties/classFieldInsideLocalInSetter.kt +++ b/compiler/testData/codegen/box/properties/classFieldInsideLocalInSetter.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR class My { var my: String = "U" get() = { field }() diff --git a/compiler/testData/codegen/box/properties/const/constFlags.kt b/compiler/testData/codegen/box/properties/const/constFlags.kt index 807dddd12b3..2dcb7c4fb72 100644 --- a/compiler/testData/codegen/box/properties/const/constFlags.kt +++ b/compiler/testData/codegen/box/properties/const/constFlags.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt b/compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt index 3745a18498f..ef34dbb68b6 100644 --- a/compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt +++ b/compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/call/privateProperty.kt b/compiler/testData/codegen/box/reflection/call/privateProperty.kt index 90ee9702492..07aa9ed134b 100644 --- a/compiler/testData/codegen/box/reflection/call/privateProperty.kt +++ b/compiler/testData/codegen/box/reflection/call/privateProperty.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/genericSignature/kt5112.kt b/compiler/testData/codegen/box/reflection/genericSignature/kt5112.kt index 22c60fdfcac..b7f4042a2c9 100644 --- a/compiler/testData/codegen/box/reflection/genericSignature/kt5112.kt +++ b/compiler/testData/codegen/box/reflection/genericSignature/kt5112.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/properties/getPropertiesMutableVsReadonly.kt b/compiler/testData/codegen/box/reflection/properties/getPropertiesMutableVsReadonly.kt index c191ba38c28..a972e386396 100644 --- a/compiler/testData/codegen/box/reflection/properties/getPropertiesMutableVsReadonly.kt +++ b/compiler/testData/codegen/box/reflection/properties/getPropertiesMutableVsReadonly.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/properties/privateClassVar.kt b/compiler/testData/codegen/box/reflection/properties/privateClassVar.kt index 11a966922eb..46b81bab9a3 100644 --- a/compiler/testData/codegen/box/reflection/properties/privateClassVar.kt +++ b/compiler/testData/codegen/box/reflection/properties/privateClassVar.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt b/compiler/testData/codegen/box/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt index ead1dcd517a..c125c28b29f 100644 --- a/compiler/testData/codegen/box/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt +++ b/compiler/testData/codegen/box/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/properties/propertyOfNestedClassAndArrayType.kt b/compiler/testData/codegen/box/reflection/properties/propertyOfNestedClassAndArrayType.kt index 46a8eb3991b..e251b8cf449 100644 --- a/compiler/testData/codegen/box/reflection/properties/propertyOfNestedClassAndArrayType.kt +++ b/compiler/testData/codegen/box/reflection/properties/propertyOfNestedClassAndArrayType.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/reflection/properties/protectedClassVar.kt b/compiler/testData/codegen/box/reflection/properties/protectedClassVar.kt index 8651be728a8..00974d571af 100644 --- a/compiler/testData/codegen/box/reflection/properties/protectedClassVar.kt +++ b/compiler/testData/codegen/box/reflection/properties/protectedClassVar.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/statics/inheritedPropertyInClassObject.kt b/compiler/testData/codegen/box/statics/inheritedPropertyInClassObject.kt index c448aca626a..2ab591a3f58 100644 --- a/compiler/testData/codegen/box/statics/inheritedPropertyInClassObject.kt +++ b/compiler/testData/codegen/box/statics/inheritedPropertyInClassObject.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR open class Bar(val prop: String) class Foo { companion object : Bar("OK") { diff --git a/compiler/testData/codegen/box/statics/inheritedPropertyInObject.kt b/compiler/testData/codegen/box/statics/inheritedPropertyInObject.kt index df06e683133..4d00f209f61 100644 --- a/compiler/testData/codegen/box/statics/inheritedPropertyInObject.kt +++ b/compiler/testData/codegen/box/statics/inheritedPropertyInObject.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR open class Bar(val prop: String) object Foo : Bar("OK") { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 8aefaaf8003..a91a224a44c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13435,6 +13435,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt"); } + @TestMetadata("initializersOrder.kt") + public void testInitializersOrder() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt"); + } + @TestMetadata("interfaceCompanion.kt") public void testInterfaceCompanion() throws Exception { runTest("compiler/testData/codegen/box/jvmField/interfaceCompanion.kt"); @@ -13450,6 +13455,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvmField/publicField.kt"); } + @TestMetadata("publicFieldJava.kt") + public void testPublicFieldJava() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/publicFieldJava.kt"); + } + @TestMetadata("simpleMemberProperty.kt") public void testSimpleMemberProperty() throws Exception { runTest("compiler/testData/codegen/box/jvmField/simpleMemberProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 33f7fe5f3c6..8a7b4b3e300 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13435,6 +13435,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt"); } + @TestMetadata("initializersOrder.kt") + public void testInitializersOrder() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt"); + } + @TestMetadata("interfaceCompanion.kt") public void testInterfaceCompanion() throws Exception { runTest("compiler/testData/codegen/box/jvmField/interfaceCompanion.kt"); @@ -13450,6 +13455,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/jvmField/publicField.kt"); } + @TestMetadata("publicFieldJava.kt") + public void testPublicFieldJava() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/publicFieldJava.kt"); + } + @TestMetadata("simpleMemberProperty.kt") public void testSimpleMemberProperty() throws Exception { runTest("compiler/testData/codegen/box/jvmField/simpleMemberProperty.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9f782d33451..87db88d921b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13440,6 +13440,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt"); } + @TestMetadata("initializersOrder.kt") + public void testInitializersOrder() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt"); + } + @TestMetadata("interfaceCompanion.kt") public void testInterfaceCompanion() throws Exception { runTest("compiler/testData/codegen/box/jvmField/interfaceCompanion.kt"); @@ -13455,6 +13460,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvmField/publicField.kt"); } + @TestMetadata("publicFieldJava.kt") + public void testPublicFieldJava() throws Exception { + runTest("compiler/testData/codegen/box/jvmField/publicFieldJava.kt"); + } + @TestMetadata("simpleMemberProperty.kt") public void testSimpleMemberProperty() throws Exception { runTest("compiler/testData/codegen/box/jvmField/simpleMemberProperty.kt");