JVM_IR: refactor MoveCompanionObjectFieldsLowering
* Extract replacement of IrGetField/IrSetField into a separate file-level lowering (should reduce the amount of work to linear in the number of classes rather than potentially quadratic) * Extract static backing field construction into JvmDeclarationFactory and move that lowering after PropertiesToFields lowering to reduce code duplication
This commit is contained in:
@@ -225,6 +225,7 @@ private val jvmFilePhases =
|
||||
propertyReferencePhase then
|
||||
constPhase then
|
||||
propertiesToFieldsPhase then
|
||||
remapObjectFieldAccesses then
|
||||
propertiesPhase then
|
||||
renameFieldsPhase then
|
||||
anonymousObjectSuperConstructorPhase then
|
||||
|
||||
+33
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.MethodSignatureMapper
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -37,6 +39,7 @@ class JvmDeclarationFactory(
|
||||
private val interfaceCompanionFieldDeclarations = HashMap<IrSymbolOwner, IrField>()
|
||||
private val outerThisDeclarations = HashMap<IrClass, IrField>()
|
||||
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
|
||||
private val staticBackingFields = HashMap<IrProperty, IrField>()
|
||||
|
||||
private val defaultImplsMethods = HashMap<IrSimpleFunction, IrSimpleFunction>()
|
||||
private val defaultImplsClasses = HashMap<IrClass, IrClass>()
|
||||
@@ -152,6 +155,36 @@ class JvmDeclarationFactory(
|
||||
else
|
||||
getFieldForObjectInstance(singleton)
|
||||
|
||||
fun getStaticBackingField(irProperty: IrProperty): IrField? {
|
||||
// Only fields defined directly in objects should be made static.
|
||||
// Fake overrides never point to those, as objects are final.
|
||||
if (irProperty.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return null
|
||||
val oldField = irProperty.backingField ?: return null
|
||||
val oldParent = irProperty.parent as? IrClass ?: return null
|
||||
if (!oldParent.isObject) return null
|
||||
return staticBackingFields.getOrPut(irProperty) {
|
||||
buildField {
|
||||
updateFrom(oldField)
|
||||
name = oldField.name
|
||||
isStatic = true
|
||||
}.apply {
|
||||
// We don't move fields to interfaces unless all fields are annotated with @JvmField.
|
||||
// It is an error to annotate only some of the fields of an interface companion with
|
||||
// @JvmField, so checking the current field only should be enough.
|
||||
val hasJvmField = oldField.hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME)
|
||||
parent = if (oldParent.isCompanion && (!oldParent.parentAsClass.isJvmInterface || hasJvmField))
|
||||
oldParent.parentAsClass
|
||||
else
|
||||
oldParent
|
||||
annotations += oldField.annotations
|
||||
initializer = oldField.initializer
|
||||
?.replaceThisByStaticReference(this@JvmDeclarationFactory, oldParent, oldParent.thisReceiver!!)
|
||||
?.deepCopyWithSymbols(this) as IrExpressionBody?
|
||||
(this as IrFieldImpl).metadata = oldField.metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDefaultImplsFunction(interfaceFun: IrSimpleFunction): IrSimpleFunction {
|
||||
val parent = interfaceFun.parentAsClass
|
||||
assert(parent.isJvmInterface) { "Parent of ${interfaceFun.dump()} should be interface" }
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.lower.IrLoweringContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmSymbols
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -152,14 +153,14 @@ fun IrExpression.isSmartcastFromHigherThanNullable(context: JvmBackendContext) =
|
||||
!this.argument.type.isSubtypeOf(type.makeNullable(), context.irBuiltIns)
|
||||
|
||||
fun IrBody.replaceThisByStaticReference(
|
||||
context: JvmBackendContext,
|
||||
declarationFactory: JvmDeclarationFactory,
|
||||
irClass: IrClass,
|
||||
oldThisReceiverParameter: IrValueParameter
|
||||
): IrBody =
|
||||
transform(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
if (expression.symbol == oldThisReceiverParameter.symbol) {
|
||||
val instanceField = context.declarationFactory.getPrivateFieldForObjectInstance(irClass)
|
||||
val instanceField = declarationFactory.getPrivateFieldForObjectInstance(irClass)
|
||||
return IrGetFieldImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
|
||||
+1
-1
@@ -181,7 +181,7 @@ private class SingletonObjectJvmStaticLowering(
|
||||
}
|
||||
|
||||
fun modifyBody(irFunction: IrFunction, irClass: IrClass, oldDispatchReceiverParameter: IrValueParameter) {
|
||||
irFunction.body = irFunction.body?.replaceThisByStaticReference(context, irClass, oldDispatchReceiverParameter)
|
||||
irFunction.body = irFunction.body?.replaceThisByStaticReference(context.declarationFactory, irClass, oldDispatchReceiverParameter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+76
-166
@@ -6,34 +6,20 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||
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.descriptors.WrappedFieldDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
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.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
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
|
||||
|
||||
internal val moveOrCopyCompanionObjectFieldsPhase = makeIrFilePhase(
|
||||
::MoveOrCopyCompanionObjectFieldsLowering,
|
||||
@@ -41,186 +27,110 @@ internal val moveOrCopyCompanionObjectFieldsPhase = makeIrFilePhase(
|
||||
description = "Move and/or copy companion object fields to static fields of companion's owner"
|
||||
)
|
||||
|
||||
internal val remapObjectFieldAccesses = makeIrFilePhase(
|
||||
::RemapObjectFieldAccesses,
|
||||
name = "RemapObjectFieldAccesses",
|
||||
description = "Make IrGetField/IrSetField to objects' fields point to the static versions",
|
||||
prerequisite = setOf(propertiesToFieldsPhase)
|
||||
)
|
||||
|
||||
private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
val fieldReplacementMap = mutableMapOf<IrFieldSymbol, IrFieldSymbol>()
|
||||
if (irClass.isObject && !irClass.isCompanion && irClass.visibility != Visibilities.LOCAL) {
|
||||
handleObject(irClass, fieldReplacementMap)
|
||||
if (irClass.isObject && !irClass.isCompanion) {
|
||||
irClass.handle()
|
||||
} else {
|
||||
handleClass(irClass, fieldReplacementMap)
|
||||
if (irClass.isJvmInterface)
|
||||
copyConsts(irClass)
|
||||
(irClass.declarations.singleOrNull { it is IrClass && it.isCompanion } as IrClass?)?.handle()
|
||||
}
|
||||
irClass.replaceFieldReferences(fieldReplacementMap)
|
||||
}
|
||||
|
||||
private fun handleObject(irObject: IrClass, fieldReplacementMap: MutableMap<IrFieldSymbol, IrFieldSymbol>) {
|
||||
irObject.declarations.replaceAll {
|
||||
private fun IrClass.handle() {
|
||||
val newDeclarations = declarations.map {
|
||||
when (it) {
|
||||
is IrProperty -> {
|
||||
// The field is not actually moved, just replaced by a static field
|
||||
movePropertyFieldToStaticParent(it, irObject, irObject, fieldReplacementMap)
|
||||
it
|
||||
is IrProperty -> context.declarationFactory.getStaticBackingField(it)?.also { newField ->
|
||||
it.backingField = newField
|
||||
newField.correspondingPropertySymbol = it.symbol
|
||||
}
|
||||
is IrAnonymousInitializer -> moveAnonymousInitializerToStaticParent(it, irObject, irObject)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleClass(irClass: IrClass, fieldReplacementMap: MutableMap<IrFieldSymbol, IrFieldSymbol>) {
|
||||
val companion = irClass.declarations.find {
|
||||
it is IrClass && it.isCompanion
|
||||
} as IrClass? ?: return
|
||||
|
||||
// We don't move fields to interfaces unless all fields are annotated with @JvmField.
|
||||
// It is an error to annotate only some of the fields of an interface companion with @JvmField.
|
||||
val newParent = if (irClass.isJvmInterface && !companion.allFieldsAreJvmField()) companion else irClass
|
||||
|
||||
val newDeclarations = companion.declarations.map {
|
||||
when (it) {
|
||||
is IrProperty ->
|
||||
movePropertyFieldToStaticParent(it, companion, newParent, fieldReplacementMap)
|
||||
is IrAnonymousInitializer ->
|
||||
moveAnonymousInitializerToStaticParent(it, companion, newParent)
|
||||
else ->
|
||||
null
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
if (newParent === companion) {
|
||||
// Keep fields as children of `IrProperty`, but replace anonymous initializers with static ones,
|
||||
// preserving the relative ordering of anonymous initializers and property initializers.
|
||||
for ((i, declaration) in newDeclarations.withIndex())
|
||||
if (declaration is IrAnonymousInitializer)
|
||||
companion.declarations[i] = declaration
|
||||
val companionParent = if (isCompanion) parentAsClass else null
|
||||
// In case a companion contains no fields, move the anonymous initializers to the parent
|
||||
// anyway, as otherwise there will probably be no references to the companion class at all
|
||||
// and therefore its class initializer will never be invoked.
|
||||
val newParent = newDeclarations.firstOrNull { it != null }?.parentAsClass ?: companionParent ?: this
|
||||
if (newParent === this) {
|
||||
declarations.replaceAll {
|
||||
// Anonymous initializers must be made static to correctly initialize the new static
|
||||
// fields when the class is loaded.
|
||||
if (it is IrAnonymousInitializer) makeAnonymousInitializerStatic(it, newParent) else it
|
||||
}
|
||||
|
||||
if (companionParent != null) {
|
||||
for (declaration in declarations) {
|
||||
if (declaration is IrProperty && declaration.isConst && declaration.hasPublicVisibility) {
|
||||
copyConstField(declaration.backingField!!, companionParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Move all touched declarations to the parent.
|
||||
companion.declarations.removeAll { it is IrAnonymousInitializer }
|
||||
newDeclarations.filterNotNullTo(newParent.declarations)
|
||||
// Anonymous initializers must also be moved and their ordering relative to the fields
|
||||
// must be preserved, as the fields can have expression initializers themselves.
|
||||
for ((i, newField) in newDeclarations.withIndex()) {
|
||||
if (newField != null)
|
||||
newParent.declarations += newField
|
||||
if (declarations[i] is IrAnonymousInitializer)
|
||||
newParent.declarations += makeAnonymousInitializerStatic(declarations[i] as IrAnonymousInitializer, newParent)
|
||||
}
|
||||
declarations.removeAll { it is IrAnonymousInitializer }
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyConsts(irClass: IrClass) {
|
||||
val companion = irClass.declarations.find {
|
||||
it is IrClass && it.isCompanion
|
||||
} as IrClass? ?: return
|
||||
companion.declarations.filter { it is IrProperty && it.isConst && it.hasPublicVisibility }
|
||||
.mapNotNullTo(irClass.declarations) { copyPropertyFieldToStaticParent(it as IrProperty, companion, irClass) }
|
||||
}
|
||||
|
||||
private val IrProperty.hasPublicVisibility: Boolean
|
||||
get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.PROTECTED
|
||||
|
||||
private fun IrClass.allFieldsAreJvmField() =
|
||||
declarations.filterIsInstance<IrProperty>()
|
||||
.mapNotNull { it.backingField }.all { it.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) }
|
||||
|
||||
// If fieldReplacementMap is null / unspecified, keep the old field and don't update the references.
|
||||
private fun moveOrCopyPropertyFieldToStaticParent(
|
||||
irProperty: IrProperty,
|
||||
propertyParent: IrClass,
|
||||
fieldParent: IrClass,
|
||||
fieldReplacementMap: MutableMap<IrFieldSymbol, IrFieldSymbol>? = null
|
||||
): IrField? {
|
||||
if (irProperty.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return null
|
||||
val oldField = irProperty.backingField ?: return null
|
||||
val newField = createStaticBackingField(oldField, propertyParent, fieldParent)
|
||||
|
||||
fieldReplacementMap?.run {
|
||||
irProperty.backingField = newField
|
||||
newField.correspondingPropertySymbol = irProperty.symbol
|
||||
put(oldField.symbol, newField.symbol)
|
||||
}
|
||||
|
||||
return newField
|
||||
}
|
||||
|
||||
private fun movePropertyFieldToStaticParent(
|
||||
irProperty: IrProperty,
|
||||
propertyParent: IrClass,
|
||||
fieldParent: IrClass,
|
||||
fieldReplacementMap: MutableMap<IrFieldSymbol, IrFieldSymbol>? = null
|
||||
): IrField? = moveOrCopyPropertyFieldToStaticParent(irProperty, propertyParent, fieldParent, fieldReplacementMap)
|
||||
|
||||
private fun copyPropertyFieldToStaticParent(
|
||||
irProperty: IrProperty,
|
||||
propertyParent: IrClass,
|
||||
fieldParent: IrClass
|
||||
): IrField? = moveOrCopyPropertyFieldToStaticParent(irProperty, propertyParent, fieldParent)
|
||||
|
||||
private fun moveAnonymousInitializerToStaticParent(
|
||||
oldInitializer: IrAnonymousInitializer,
|
||||
oldParent: IrClass,
|
||||
newParent: IrClass
|
||||
): IrAnonymousInitializer =
|
||||
private fun makeAnonymousInitializerStatic(oldInitializer: IrAnonymousInitializer, newParent: IrClass) =
|
||||
with(oldInitializer) {
|
||||
IrAnonymousInitializerImpl(
|
||||
startOffset, endOffset, origin, IrAnonymousInitializerSymbolImpl(newParent.symbol),
|
||||
isStatic = true
|
||||
).apply {
|
||||
val oldParent = parentAsClass
|
||||
val newSymbol = IrAnonymousInitializerSymbolImpl(newParent.symbol)
|
||||
IrAnonymousInitializerImpl(startOffset, endOffset, origin, newSymbol, isStatic = true).apply {
|
||||
parent = newParent
|
||||
body = oldInitializer.body
|
||||
.replaceThisByStaticReference(context, oldParent, oldParent.thisReceiver!!)
|
||||
body = this@with.body
|
||||
.replaceThisByStaticReference(context.declarationFactory, oldParent, oldParent.thisReceiver!!)
|
||||
.patchDeclarationParents(newParent) as IrBlockBody
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStaticBackingField(oldField: IrField, propertyParent: IrClass, fieldParent: IrClass): IrField {
|
||||
val descriptor = WrappedFieldDescriptor(oldField.descriptor.annotations, oldField.descriptor.source)
|
||||
val field = IrFieldImpl(
|
||||
oldField.startOffset, oldField.endOffset,
|
||||
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
|
||||
IrFieldSymbolImpl(descriptor),
|
||||
oldField.name, oldField.type, oldField.visibility,
|
||||
isFinal = oldField.isFinal,
|
||||
isExternal = oldField.isExternal,
|
||||
isStatic = true,
|
||||
isFakeOverride = false
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
parent = fieldParent
|
||||
annotations.addAll(oldField.annotations)
|
||||
metadata = oldField.metadata
|
||||
private fun copyConstField(oldField: IrField, newParent: IrClass) =
|
||||
newParent.addField {
|
||||
updateFrom(oldField)
|
||||
name = oldField.name
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = newParent
|
||||
annotations += oldField.annotations
|
||||
initializer = oldField.initializer?.deepCopyWithSymbols(this)
|
||||
}
|
||||
val oldInitializer = oldField.initializer
|
||||
if (oldInitializer != null) {
|
||||
field.initializer = oldInitializer
|
||||
.replaceThisByStaticReference(context, propertyParent, propertyParent.thisReceiver!!)
|
||||
.deepCopyWithSymbols(field) as IrExpressionBody
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrElement.replaceFieldReferences(replacementMap: Map<IrFieldSymbol, IrFieldSymbol>) {
|
||||
transformChildrenVoid(FieldReplacer(replacementMap))
|
||||
}
|
||||
private class RemapObjectFieldAccesses(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() {
|
||||
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
|
||||
|
||||
private fun IrField.remap(): IrField? =
|
||||
correspondingPropertySymbol?.owner?.let(context.declarationFactory::getStaticBackingField)
|
||||
|
||||
private class FieldReplacer(val replacementMap: Map<IrFieldSymbol, IrFieldSymbol>) : 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
|
||||
)
|
||||
expression.symbol.owner.remap()?.let {
|
||||
with(expression) {
|
||||
IrGetFieldImpl(startOffset, endOffset, it.symbol, type, /* receiver = */ null, origin, superQualifierSymbol)
|
||||
}
|
||||
} ?: super.visitGetField(expression)
|
||||
|
||||
override fun visitSetField(expression: IrSetField): IrExpression =
|
||||
replacementMap[expression.symbol]?.let { _ ->
|
||||
IrSetFieldImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
replacementMap.getValue(expression.symbol),
|
||||
/* receiver = */ null,
|
||||
visitExpression(expression.value),
|
||||
expression.type,
|
||||
expression.origin,
|
||||
expression.superQualifierSymbol
|
||||
)
|
||||
expression.symbol.owner.remap()?.let {
|
||||
with(expression) {
|
||||
val newValue = value.transform(this@RemapObjectFieldAccesses, null)
|
||||
IrSetFieldImpl(startOffset, endOffset, it.symbol, /* receiver = */ null, newValue, type, origin, superQualifierSymbol)
|
||||
}
|
||||
} ?: super.visitSetField(expression)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: box.kt
|
||||
fun box(): String = Z.result
|
||||
|
||||
// FILE: z.kt
|
||||
object Z {
|
||||
@JvmField
|
||||
val result: String = "OK"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: box.kt
|
||||
fun box(): String = A.result
|
||||
|
||||
object A {
|
||||
@JvmField
|
||||
val result: String
|
||||
|
||||
init { result = Z.result }
|
||||
}
|
||||
|
||||
// FILE: z.kt
|
||||
object Z {
|
||||
@JvmField
|
||||
val result: String = "OK"
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: +JvmFieldInInterface +NestedClassesInAnnotations
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: +JvmFieldInInterface
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_RUNTIME
|
||||
|
||||
+10
@@ -15058,6 +15058,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrder.kt")
|
||||
public void testFileOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrderWithCopying.kt")
|
||||
public void testFileOrderWithCopying() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrderWithCopying.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("initializersOrder.kt")
|
||||
public void testInitializersOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt");
|
||||
|
||||
+10
@@ -15058,6 +15058,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrder.kt")
|
||||
public void testFileOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrderWithCopying.kt")
|
||||
public void testFileOrderWithCopying() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrderWithCopying.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("initializersOrder.kt")
|
||||
public void testInitializersOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt");
|
||||
|
||||
+10
@@ -13913,6 +13913,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrder.kt")
|
||||
public void testFileOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrderWithCopying.kt")
|
||||
public void testFileOrderWithCopying() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrderWithCopying.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("initializersOrder.kt")
|
||||
public void testInitializersOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt");
|
||||
|
||||
+10
@@ -13913,6 +13913,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/jvmField/constructorProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrder.kt")
|
||||
public void testFileOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileOrderWithCopying.kt")
|
||||
public void testFileOrderWithCopying() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/fileOrderWithCopying.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("initializersOrder.kt")
|
||||
public void testInitializersOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmField/initializersOrder.kt");
|
||||
|
||||
Reference in New Issue
Block a user