From e42a4b2fac7b076b8e8ecd1f78642de98739608d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 17 Jan 2020 19:56:29 +0100 Subject: [PATCH] IR: extract JvmPropertiesLowering out of PropertiesLowering --- .../common/lower/PropertiesLowering.kt | 77 ++------------ .../kotlin/ir/backend/js/JsLoweringPhases.kt | 2 +- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 20 +--- .../jvm/lower/JvmPropertiesLowering.kt | 100 ++++++++++++++++++ .../kotlin/backend/wasm/WasmLoweringPhases.kt | 4 +- 5 files changed, 114 insertions(+), 89 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt 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 38db4d5c52b..8196269c390 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 @@ -5,103 +5,42 @@ package org.jetbrains.kotlin.backend.common.lower -import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.ir.copyTo -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.Modality 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.descriptors.WrappedSimpleFunctionDescriptor -import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.types.classifierOrFail -import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat import org.jetbrains.kotlin.ir.visitors.* -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.* -class PropertiesLowering( - private val context: BackendContext, - private val originOfSyntheticMethodForAnnotations: IrDeclarationOrigin? = null, - private val skipExternalProperties: Boolean = false, - private val generateAnnotationFields: Boolean = false, - private val computeSyntheticMethodName: ((IrProperty) -> String)? = null -) : IrElementTransformerVoid(), FileLoweringPass { +class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass { override fun lower(irFile: IrFile) { irFile.accept(this, null) } override fun visitFile(declaration: IrFile): IrFile { declaration.transformChildrenVoid(this) - declaration.transformDeclarationsFlat { lowerProperty(it, ClassKind.CLASS) } + declaration.transformDeclarationsFlat { lowerProperty(it) } return declaration } override fun visitClass(declaration: IrClass): IrStatement { declaration.transformChildrenVoid(this) - declaration.transformDeclarationsFlat { lowerProperty(it, declaration.kind) } + declaration.transformDeclarationsFlat { lowerProperty(it) } return declaration } override fun visitScript(declaration: IrScript): IrStatement { declaration.transformChildrenVoid(this) - declaration.transformDeclarationsFlat { lowerProperty(it, ClassKind.CLASS) } + declaration.transformDeclarationsFlat { lowerProperty(it) } return declaration } - private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List? = - if (declaration is IrProperty) - if (skipExternalProperties && declaration.isEffectivelyExternal()) listOf(declaration) else { - ArrayList(4).apply { - // JvmFields in a companion object refer to companion's owners and should not be generated within companion. - if (generateAnnotationFields || (kind != ClassKind.ANNOTATION_CLASS && declaration.backingField?.parent == declaration.parent)) { - addIfNotNull(declaration.backingField) - } - addIfNotNull(declaration.getter) - addIfNotNull(declaration.setter) - - if (declaration.annotations.isNotEmpty() && originOfSyntheticMethodForAnnotations != null - && computeSyntheticMethodName != null - ) { - val methodName = computeSyntheticMethodName.invoke(declaration) // Workaround KT-4113 - add(createSyntheticMethodForAnnotations(declaration, originOfSyntheticMethodForAnnotations, methodName)) - } - } - } - else - null - - private fun createSyntheticMethodForAnnotations(declaration: IrProperty, origin: IrDeclarationOrigin, name: String): IrFunctionImpl { - val descriptor = WrappedSimpleFunctionDescriptor(declaration.descriptor.annotations) - val symbol = IrSimpleFunctionSymbolImpl(descriptor) - return IrFunctionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, Name.identifier(name), - declaration.visibility, Modality.OPEN, context.irBuiltIns.unitType, - isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isExpect = false, isFakeOverride = false, - isOperator = false - ).apply { - descriptor.bind(this) - - val extensionReceiver = declaration.getter?.extensionReceiverParameter - if (extensionReceiver != null) { - // Use raw type of extension receiver to avoid generic signature, which would be useless for this method. - extensionReceiverParameter = extensionReceiver.copyTo(this, type = extensionReceiver.type.classifierOrFail.typeWith()) - } - - body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) - - annotations.addAll(declaration.annotations) - metadata = declaration.metadata - } - } + private fun lowerProperty(declaration: IrDeclaration): List? = + if (declaration is IrProperty && !declaration.isEffectivelyExternal()) + listOfNotNull(declaration.backingField, declaration.getter, declaration.setter) + else null companion object { fun checkNoProperties(irFile: IrFile) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index df9eeeda2eb..12d1e522e97 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -268,7 +268,7 @@ private val varargLoweringPhase = makeJsModulePhase( ) private val propertiesLoweringPhase = makeJsModulePhase( - { context -> PropertiesLowering(context, skipExternalProperties = true, generateAnnotationFields = true) }, + { PropertiesLowering() }, name = "PropertiesLowering", description = "Move fields and accessors out from its property" ) 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 749320eafda..7b4878c7de7 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 @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.jvm.lower.* -import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.IrElement @@ -24,7 +23,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.load.java.JavaVisibilities -import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.NameUtils private fun makePatchParentsPhase(number: Int) = namedIrFilePhase( @@ -87,22 +85,10 @@ private val lateinitPhase = makeIrFilePhase( description = "Insert checks for lateinit field references" ) -private val propertiesPhase = makeIrFilePhase( - { context -> - PropertiesLowering(context, JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS) { property -> - val baseName = - if (context.state.languageVersionSettings.supportsFeature(LanguageFeature.UseGetterNameForPropertyAnnotationsMethodOnJvm)) { - property.getter?.let { getter -> - context.methodSignatureMapper.mapFunctionName(getter) - } ?: JvmAbi.getterName(property.name.asString()) - } else { - property.name.asString() - } - JvmAbi.getSyntheticMethodNameForAnnotatedProperty(baseName) - } - }, +private val propertiesPhase = makeIrFilePhase( + ::JvmPropertiesLowering, name = "Properties", - description = "Move fields and accessors for properties to their classes", + description = "Move fields and accessors for properties to their classes, and create synthetic methods for property annotations", stickyPostconditions = setOf((PropertiesLowering)::checkNoProperties) ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt new file mode 100644 index 00000000000..1f4fd25d6b9 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.FileLoweringPass +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +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.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.types.classifierOrFail +import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addIfNotNull +import java.util.* + +class JvmPropertiesLowering(private val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + override fun lower(irFile: IrFile) { + irFile.accept(this, null) + } + + override fun visitClass(declaration: IrClass): IrStatement { + declaration.transformChildrenVoid(this) + declaration.transformDeclarationsFlat { lowerProperty(it, declaration.kind) } + return declaration + } + + private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List? = + if (declaration is IrProperty) + ArrayList(4).apply { + // 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) + addIfNotNull(declaration.setter) + + if (declaration.annotations.isNotEmpty()) { + add(createSyntheticMethodForAnnotations(declaration)) + } + } + else + null + + private fun createSyntheticMethodForAnnotations(declaration: IrProperty): IrFunctionImpl { + val descriptor = WrappedSimpleFunctionDescriptor(declaration.descriptor.annotations) + val symbol = IrSimpleFunctionSymbolImpl(descriptor) + val name = computeSyntheticMethodName(declaration) + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS, symbol, + Name.identifier(name), declaration.visibility, Modality.OPEN, context.irBuiltIns.unitType, + isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isExpect = false, isFakeOverride = false, + isOperator = false + ).apply { + descriptor.bind(this) + + val extensionReceiver = declaration.getter?.extensionReceiverParameter + if (extensionReceiver != null) { + // Use raw type of extension receiver to avoid generic signature, which would be useless for this method. + extensionReceiverParameter = extensionReceiver.copyTo(this, type = extensionReceiver.type.classifierOrFail.typeWith()) + } + + body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) + parent = declaration.parent + + annotations.addAll(declaration.annotations) + metadata = declaration.metadata + } + } + + private fun computeSyntheticMethodName(property: IrProperty): String { + val baseName = + if (context.state.languageVersionSettings.supportsFeature(LanguageFeature.UseGetterNameForPropertyAnnotationsMethodOnJvm)) { + property.getter?.let { getter -> + context.methodSignatureMapper.mapFunctionName(getter) + } ?: JvmAbi.getterName(property.name.asString()) + } else { + property.name.asString() + } + return JvmAbi.getSyntheticMethodNameForAnnotatedProperty(baseName) + } +} diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 2f463ec61a6..12fb4a15e40 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -190,7 +190,7 @@ private val defaultParameterCleanerPhase = makeWasmModulePhase( //) private val propertiesLoweringPhase = makeWasmModulePhase( - { context -> PropertiesLowering(context, skipExternalProperties = true, generateAnnotationFields = true) }, + { PropertiesLowering() }, name = "PropertiesLowering", description = "Move fields and accessors out from its property" ) @@ -399,4 +399,4 @@ val wasmPhases = namedIrModulePhase( staticMembersLoweringPhase then validateIrAfterLowering -) \ No newline at end of file +)