PrivateMembersLowering
This commit is contained in:
committed by
Anton Bannykh
parent
f6d4ea469c
commit
3165556c6b
@@ -50,8 +50,6 @@ class JsIrBackendContext(
|
||||
override val lateinitNullableFields
|
||||
get() = error("Use Mapping.lateInitFieldToNullableField instead")
|
||||
|
||||
val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
|
||||
override var inVerbosePhase: Boolean = false
|
||||
|
||||
@@ -247,6 +247,12 @@ private val privateMembersLoweringPhase = makeJsModulePhase(
|
||||
description = "Extract private members from classes"
|
||||
)
|
||||
|
||||
private val privateMemberUsagesLoweringPhase = makeJsModulePhase(
|
||||
::PrivateMemberBodiesLowering,
|
||||
name = "PrivateMemberUsagesLowering",
|
||||
description = "Rewrite the private member usages"
|
||||
)
|
||||
|
||||
private val callableReferenceLoweringPhase = makeJsModulePhase(
|
||||
::CallableReferenceLowering,
|
||||
name = "CallableReferenceLowering",
|
||||
@@ -486,6 +492,7 @@ val jsPhases = namedIrModulePhase(
|
||||
propertyAccessorInlinerLoweringPhase then
|
||||
foldConstantLoweringPhase then
|
||||
privateMembersLoweringPhase then
|
||||
privateMemberUsagesLoweringPhase then
|
||||
callableReferenceLoweringPhase then
|
||||
defaultArgumentStubGeneratorPhase then
|
||||
defaultArgumentPatchOverridesPhase then
|
||||
|
||||
@@ -18,4 +18,5 @@ class JsMapping : DefaultMapping() {
|
||||
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
|
||||
val objectToInstanceField = newMapping<IrClass, IrField>()
|
||||
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
||||
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
|
||||
}
|
||||
+124
-121
@@ -5,10 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -17,56 +17,143 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
|
||||
|
||||
class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val memberMap = context.memberMap
|
||||
class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
transformPrivateDeclarations(irFile)
|
||||
transformPrivateUseSites(irFile)
|
||||
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return when (declaration) {
|
||||
is IrSimpleFunction -> transformMemberToStaticFunction(declaration)?.let { staticFunction ->
|
||||
declaration.correspondingStatic = staticFunction
|
||||
listOf(staticFunction)
|
||||
}
|
||||
is IrProperty -> listOf(declaration.apply {
|
||||
// Detach old function from corresponding property
|
||||
this.getter = this.getter?.let { g -> transformAccessor(g) }
|
||||
this.setter = this.setter?.let { s -> transformAccessor(s) }
|
||||
})
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformPrivateDeclarations(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
declaration.declarations.transformFlat {
|
||||
when (it) {
|
||||
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction ->
|
||||
listOf(staticFunction)
|
||||
}
|
||||
is IrProperty -> listOf(it.apply {
|
||||
this.getter = this.getter?.let { g -> transformAccessor(g) }
|
||||
this.setter = this.setter?.let { s -> transformAccessor(s) }
|
||||
})
|
||||
else -> null
|
||||
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
|
||||
|
||||
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
|
||||
|
||||
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
|
||||
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||
val staticFunction = function.run {
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin,
|
||||
symbol, name, visibility, modality,
|
||||
returnType,
|
||||
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
|
||||
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
|
||||
isOperator = isOperator
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = parent
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
|
||||
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
|
||||
|
||||
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
|
||||
val thisDesc = WrappedValueParameterDescriptor()
|
||||
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
|
||||
staticFunction.valueParameters += IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
STATIC_THIS_PARAMETER,
|
||||
thisSymbol,
|
||||
Name.identifier("\$this"),
|
||||
0,
|
||||
function.dispatchReceiverParameter!!.type,
|
||||
null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).also {
|
||||
thisDesc.bind(it)
|
||||
it.parent = staticFunction
|
||||
}
|
||||
|
||||
function.correspondingStatic = staticFunction
|
||||
|
||||
staticFunction.valueParameters += function.valueParameters.map {
|
||||
// TODO better way to avoid copying default value
|
||||
it.copyTo(staticFunction, index = it.index + 1, defaultValue = null)
|
||||
}
|
||||
|
||||
val oldParameters =
|
||||
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
|
||||
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
|
||||
assert(oldParameters.size == newParameters.size)
|
||||
|
||||
val parameterMapping = oldParameters.zip(newParameters).toMap()
|
||||
|
||||
val parameterTransformer = object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
|
||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
|
||||
} ?: expression
|
||||
}
|
||||
|
||||
fun IrBody.copyWithParameters(): IrBody {
|
||||
return deepCopyWithSymbols(staticFunction).also {
|
||||
it.transform(parameterTransformer, null)
|
||||
}
|
||||
}
|
||||
|
||||
function.valueParameters.forEach {
|
||||
// TODO better way to avoid copying default value
|
||||
|
||||
parameterMapping[it]?.apply {
|
||||
it.defaultValue?.let { originalDefault ->
|
||||
defaultValue = IrExpressionBodyImpl(it.startOffset, it.endOffset) {
|
||||
expression = (originalDefault.copyWithParameters() as IrExpressionBody).expression
|
||||
}
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformPrivateUseSites(irFile: IrFile) {
|
||||
irFile.transform(object : IrElementTransformerVoid() {
|
||||
function.body?.let {
|
||||
staticFunction.body = when (it) {
|
||||
is IrBlockBody -> IrBlockBodyImpl(it.startOffset, it.endOffset) {
|
||||
statements += (it.copyWithParameters() as IrBlockBody).statements
|
||||
}
|
||||
is IrExpressionBody -> IrExpressionBodyImpl(it.startOffset, it.endOffset) {
|
||||
expression = (it.copyWithParameters() as IrExpressionBody).expression
|
||||
}
|
||||
is IrSyntheticBody -> it
|
||||
else -> error("Unexpected body kind: ${it.javaClass}")
|
||||
}
|
||||
}
|
||||
|
||||
return staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
class PrivateMemberBodiesLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
|
||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
||||
return expression.symbol.owner.correspondingStatic?.let {
|
||||
transformPrivateToStaticCall(expression, it)
|
||||
} ?: expression
|
||||
}
|
||||
@@ -74,7 +161,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
super.visitFunctionReference(expression)
|
||||
|
||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
||||
return expression.symbol.owner.correspondingStatic?.let {
|
||||
transformPrivateToStaticReference(expression) {
|
||||
IrFunctionReferenceImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
@@ -89,8 +176,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||
super.visitPropertyReference(expression)
|
||||
|
||||
val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) }
|
||||
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) }
|
||||
val staticGetter = expression.getter?.owner?.correspondingStatic
|
||||
val staticSetter = expression.setter?.owner?.correspondingStatic
|
||||
|
||||
return if (staticGetter != null || staticSetter != null) {
|
||||
transformPrivateToStaticReference(expression) {
|
||||
@@ -147,88 +234,4 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
|
||||
|
||||
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
|
||||
|
||||
val staticFunction = getOrPutStaticFunction(function.symbol) ?: return null
|
||||
|
||||
// Detach old function from corresponding property
|
||||
val correspondingProperty = function.correspondingPropertySymbol?.owner
|
||||
if (correspondingProperty != null) {
|
||||
when (function) {
|
||||
correspondingProperty.getter -> correspondingProperty.getter = staticFunction
|
||||
correspondingProperty.setter -> correspondingProperty.setter = staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
val oldParameters =
|
||||
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
|
||||
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
|
||||
assert(oldParameters.size == newParameters.size)
|
||||
|
||||
val parameterMapping = oldParameters.zip(newParameters).toMap()
|
||||
|
||||
staticFunction.body = function.body?.deepCopyWithSymbols(staticFunction)
|
||||
|
||||
staticFunction.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
|
||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
|
||||
} ?: expression
|
||||
}, null)
|
||||
|
||||
return staticFunction
|
||||
}
|
||||
|
||||
private fun getOrPutStaticFunction(functionSymbol: IrFunctionSymbol): IrSimpleFunction? {
|
||||
val function = functionSymbol.owner
|
||||
if (function !is IrSimpleFunction) return null
|
||||
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
|
||||
|
||||
return memberMap.getOrPut(function.symbol) {
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||
val staticFunction = function.run {
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin,
|
||||
symbol, name, visibility, modality,
|
||||
returnType,
|
||||
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
|
||||
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
|
||||
isOperator = isOperator
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = parent
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
|
||||
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
|
||||
|
||||
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
|
||||
val thisDesc = WrappedValueParameterDescriptor()
|
||||
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
|
||||
staticFunction.valueParameters += IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
STATIC_THIS_PARAMETER,
|
||||
thisSymbol,
|
||||
Name.identifier("\$this"),
|
||||
0,
|
||||
function.dispatchReceiverParameter!!.type,
|
||||
null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).also {
|
||||
thisDesc.bind(it)
|
||||
it.parent = staticFunction
|
||||
}
|
||||
|
||||
staticFunction.valueParameters += function.valueParameters.map { it.copyTo(staticFunction, index = it.index + 1) }
|
||||
|
||||
staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user