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 0f8c9d9e396..503b34be87b 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 @@ -16,7 +16,7 @@ package org.jetbrains.kotlin.backend.jvm -import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.jvm.lower.* @@ -46,7 +46,8 @@ internal val jvmPhases = namedIrFilePhase( jvmLateinitPhase then moveCompanionObjectFieldsPhase then - constAndJvmFieldPropertiesPhase then + constPhase then + propertiesToFieldsPhase then propertiesPhase then annotationPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt new file mode 100644 index 00000000000..bcc94f05153 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2019 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.CommonBackendContext +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.ir.declarations.IrFile +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.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +internal val constPhase = makeIrFilePhase( + ::ConstLowering, + name = "Const", + description = "Substitute calls to const properties with constant values" +) + +class ConstLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(this) + } + + override fun visitCall(expression: IrCall): IrExpression { + 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 } + } + + return super.visitCall(expression) + } +} 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/PropertiesToFieldsLowering.kt similarity index 65% rename from compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstAndJvmFieldPropertiesLowering.kt rename to compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertiesToFieldsLowering.kt index e31eb1141cc..1020f6364a6 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/PropertiesToFieldsLowering.kt @@ -10,9 +10,14 @@ 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.phaser.makeIrFilePhase +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.hasAnnotation @@ -20,45 +25,54 @@ 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 constAndJvmFieldPropertiesPhase = makeIrFilePhase( - ::ConstAndJvmFieldPropertiesLowering, - name = "ConstAndJvmFieldProperties", - description = "Substitute calls to const and Jvm>Field properties with const/field access" +internal val propertiesToFieldsPhase = makeIrFilePhase( + ::PropertiesToFieldsLowering, + name = "PropertiesToFields", + description = "Replace calls to default property accessors with field access and remove those accessors" ) -private class ConstAndJvmFieldPropertiesLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass { +class PropertiesToFieldsLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass { override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(this) } override fun visitProperty(declaration: IrProperty): IrStatement { - if (declaration.isConst || declaration.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) { - /*Safe or need copy?*/ + if (declaration.isConst || shouldSubstituteAccessorWithField(declaration, declaration.getter)) { declaration.getter = null + } + if (declaration.isConst || shouldSubstituteAccessorWithField(declaration, declaration.setter)) { declaration.setter = null } return super.visitProperty(declaration) } override fun visitCall(expression: IrCall): IrExpression { - val irSimpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression) - val irProperty = irSimpleFunction.correspondingProperty ?: return super.visitCall(expression) + val simpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression) + val property = simpleFunction.correspondingProperty ?: return super.visitCall(expression) - if (irProperty.isConst) { - (irProperty.backingField!!.initializer!!.expression as IrConst<*>).let { return it } - } - - if (irProperty.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) { - return if (expression is IrGetterCallImpl) { - substituteGetter(irProperty, expression) - } else { - assert(expression is IrSetterCallImpl) - substituteSetter(irProperty, expression) + if (shouldSubstituteAccessorWithField(property, simpleFunction)) { + when (expression) { + is IrGetterCallImpl -> return substituteGetter(property, expression) + is IrSetterCallImpl -> return substituteSetter(property, expression) } } + return super.visitCall(expression) } + private fun shouldSubstituteAccessorWithField(property: IrProperty, accessor: IrSimpleFunction?): Boolean { + if (accessor == null) return false + + // In contrast to the old backend, we do generate getters for lateinit properties, which fixes KT-28331 + if (property.isLateinit) return false + + if ((property.parent as? IrClass)?.kind == ClassKind.ANNOTATION_CLASS) return false + + if (property.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) return true + + return accessor.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR && Visibilities.isPrivate(accessor.visibility) + } + private fun substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression { val backingField = irProperty.backingField!! val receiver = expression.dispatchReceiver?.transform(this, null) diff --git a/compiler/testData/codegen/box/multifileClasses/kt16077.kt b/compiler/testData/codegen/box/multifileClasses/kt16077.kt index 7dc257128ca..3639809c63d 100644 --- a/compiler/testData/codegen/box/multifileClasses/kt16077.kt +++ b/compiler/testData/codegen/box/multifileClasses/kt16077.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/bytecodeText/companion/kt14258_1.kt b/compiler/testData/codegen/bytecodeText/companion/kt14258_1.kt index 9032de3a1cc..a409a0669aa 100644 --- a/compiler/testData/codegen/bytecodeText/companion/kt14258_1.kt +++ b/compiler/testData/codegen/bytecodeText/companion/kt14258_1.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // Checks that methods 'access$getMy$p', 'access$getMy$cp' and 'getMy' are not generated and // that backed field 'my' is directly used through a 'getstatic' diff --git a/compiler/testData/codegen/bytecodeText/redundantInitializer.kt b/compiler/testData/codegen/bytecodeText/redundantInitializer.kt index e45ab299e74..b074ba3c380 100644 --- a/compiler/testData/codegen/bytecodeText/redundantInitializer.kt +++ b/compiler/testData/codegen/bytecodeText/redundantInitializer.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package a class A { diff --git a/compiler/testData/codegen/bytecodeText/redundantInitializerNumber.kt b/compiler/testData/codegen/bytecodeText/redundantInitializerNumber.kt index 864372dda21..a63ee553776 100644 --- a/compiler/testData/codegen/bytecodeText/redundantInitializerNumber.kt +++ b/compiler/testData/codegen/bytecodeText/redundantInitializerNumber.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package a class A {