IR: extract JvmPropertiesLowering out of PropertiesLowering

This commit is contained in:
Alexander Udalov
2020-01-17 19:56:29 +01:00
parent 60da37404e
commit e42a4b2fac
5 changed files with 114 additions and 89 deletions
@@ -5,103 +5,42 @@
package org.jetbrains.kotlin.backend.common.lower 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.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.IrElement
import org.jetbrains.kotlin.ir.IrStatement 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.*
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.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.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
class PropertiesLowering( class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
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 {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.accept(this, null) irFile.accept(this, null)
} }
override fun visitFile(declaration: IrFile): IrFile { override fun visitFile(declaration: IrFile): IrFile {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.transformDeclarationsFlat { lowerProperty(it, ClassKind.CLASS) } declaration.transformDeclarationsFlat { lowerProperty(it) }
return declaration return declaration
} }
override fun visitClass(declaration: IrClass): IrStatement { override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.transformDeclarationsFlat { lowerProperty(it, declaration.kind) } declaration.transformDeclarationsFlat { lowerProperty(it) }
return declaration return declaration
} }
override fun visitScript(declaration: IrScript): IrStatement { override fun visitScript(declaration: IrScript): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.transformDeclarationsFlat { lowerProperty(it, ClassKind.CLASS) } declaration.transformDeclarationsFlat { lowerProperty(it) }
return declaration return declaration
} }
private fun lowerProperty(declaration: IrDeclaration, kind: ClassKind): List<IrDeclaration>? = private fun lowerProperty(declaration: IrDeclaration): List<IrDeclaration>? =
if (declaration is IrProperty) if (declaration is IrProperty && !declaration.isEffectivelyExternal())
if (skipExternalProperties && declaration.isEffectivelyExternal()) listOf(declaration) else { listOfNotNull(declaration.backingField, declaration.getter, declaration.setter)
ArrayList<IrDeclaration>(4).apply { else null
// 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
}
}
companion object { companion object {
fun checkNoProperties(irFile: IrFile) { fun checkNoProperties(irFile: IrFile) {
@@ -268,7 +268,7 @@ private val varargLoweringPhase = makeJsModulePhase(
) )
private val propertiesLoweringPhase = makeJsModulePhase( private val propertiesLoweringPhase = makeJsModulePhase(
{ context -> PropertiesLowering(context, skipExternalProperties = true, generateAnnotationFields = true) }, { PropertiesLowering() },
name = "PropertiesLowering", name = "PropertiesLowering",
description = "Move fields and accessors out from its property" description = "Move fields and accessors out from its property"
) )
@@ -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.lower.optimizations.foldConstantLoweringPhase
import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.jvm.lower.* import org.jetbrains.kotlin.backend.jvm.lower.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.IrElement 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.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.NameUtils
private fun makePatchParentsPhase(number: Int) = namedIrFilePhase( private fun makePatchParentsPhase(number: Int) = namedIrFilePhase(
@@ -87,22 +85,10 @@ private val lateinitPhase = makeIrFilePhase(
description = "Insert checks for lateinit field references" description = "Insert checks for lateinit field references"
) )
private val propertiesPhase = makeIrFilePhase<JvmBackendContext>( private val propertiesPhase = makeIrFilePhase(
{ context -> ::JvmPropertiesLowering,
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)
}
},
name = "Properties", 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) stickyPostconditions = setOf((PropertiesLowering)::checkNoProperties)
) )
@@ -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<IrDeclaration>? =
if (declaration is IrProperty)
ArrayList<IrDeclaration>(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)
}
}
@@ -190,7 +190,7 @@ private val defaultParameterCleanerPhase = makeWasmModulePhase(
//) //)
private val propertiesLoweringPhase = makeWasmModulePhase( private val propertiesLoweringPhase = makeWasmModulePhase(
{ context -> PropertiesLowering(context, skipExternalProperties = true, generateAnnotationFields = true) }, { PropertiesLowering() },
name = "PropertiesLowering", name = "PropertiesLowering",
description = "Move fields and accessors out from its property" description = "Move fields and accessors out from its property"
) )