PrivateMembersLowering
This commit is contained in:
committed by
Anton Bannykh
parent
f6d4ea469c
commit
3165556c6b
@@ -50,8 +50,6 @@ class JsIrBackendContext(
|
|||||||
override val lateinitNullableFields
|
override val lateinitNullableFields
|
||||||
get() = error("Use Mapping.lateInitFieldToNullableField instead")
|
get() = error("Use Mapping.lateInitFieldToNullableField instead")
|
||||||
|
|
||||||
val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
|
||||||
|
|
||||||
override val builtIns = module.builtIns
|
override val builtIns = module.builtIns
|
||||||
|
|
||||||
override var inVerbosePhase: Boolean = false
|
override var inVerbosePhase: Boolean = false
|
||||||
|
|||||||
@@ -247,6 +247,12 @@ private val privateMembersLoweringPhase = makeJsModulePhase(
|
|||||||
description = "Extract private members from classes"
|
description = "Extract private members from classes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val privateMemberUsagesLoweringPhase = makeJsModulePhase(
|
||||||
|
::PrivateMemberBodiesLowering,
|
||||||
|
name = "PrivateMemberUsagesLowering",
|
||||||
|
description = "Rewrite the private member usages"
|
||||||
|
)
|
||||||
|
|
||||||
private val callableReferenceLoweringPhase = makeJsModulePhase(
|
private val callableReferenceLoweringPhase = makeJsModulePhase(
|
||||||
::CallableReferenceLowering,
|
::CallableReferenceLowering,
|
||||||
name = "CallableReferenceLowering",
|
name = "CallableReferenceLowering",
|
||||||
@@ -486,6 +492,7 @@ val jsPhases = namedIrModulePhase(
|
|||||||
propertyAccessorInlinerLoweringPhase then
|
propertyAccessorInlinerLoweringPhase then
|
||||||
foldConstantLoweringPhase then
|
foldConstantLoweringPhase then
|
||||||
privateMembersLoweringPhase then
|
privateMembersLoweringPhase then
|
||||||
|
privateMemberUsagesLoweringPhase then
|
||||||
callableReferenceLoweringPhase then
|
callableReferenceLoweringPhase then
|
||||||
defaultArgumentStubGeneratorPhase then
|
defaultArgumentStubGeneratorPhase then
|
||||||
defaultArgumentPatchOverridesPhase then
|
defaultArgumentPatchOverridesPhase then
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ class JsMapping : DefaultMapping() {
|
|||||||
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
|
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
|
||||||
val objectToInstanceField = newMapping<IrClass, IrField>()
|
val objectToInstanceField = newMapping<IrClass, IrField>()
|
||||||
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
||||||
|
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
|
||||||
}
|
}
|
||||||
+124
-121
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
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.backend.common.ir.copyTo
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.WrappedSimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
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.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
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.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
|
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
|
||||||
|
|
||||||
class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
private val memberMap = context.memberMap
|
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
|
||||||
transformPrivateDeclarations(irFile)
|
|
||||||
transformPrivateUseSites(irFile)
|
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) {
|
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
|
||||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement {
|
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
|
||||||
declaration.transformChildrenVoid(this)
|
|
||||||
declaration.declarations.transformFlat {
|
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
|
||||||
when (it) {
|
|
||||||
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction ->
|
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||||
listOf(staticFunction)
|
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||||
}
|
val staticFunction = function.run {
|
||||||
is IrProperty -> listOf(it.apply {
|
IrFunctionImpl(
|
||||||
this.getter = this.getter?.let { g -> transformAccessor(g) }
|
startOffset, endOffset, origin,
|
||||||
this.setter = this.setter?.let { s -> transformAccessor(s) }
|
symbol, name, visibility, modality,
|
||||||
})
|
returnType,
|
||||||
else -> null
|
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) {
|
function.body?.let {
|
||||||
irFile.transform(object : IrElementTransformerVoid() {
|
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 {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
super.visitCall(expression)
|
super.visitCall(expression)
|
||||||
|
|
||||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
return expression.symbol.owner.correspondingStatic?.let {
|
||||||
transformPrivateToStaticCall(expression, it)
|
transformPrivateToStaticCall(expression, it)
|
||||||
} ?: expression
|
} ?: expression
|
||||||
}
|
}
|
||||||
@@ -74,7 +161,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
|||||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||||
super.visitFunctionReference(expression)
|
super.visitFunctionReference(expression)
|
||||||
|
|
||||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
return expression.symbol.owner.correspondingStatic?.let {
|
||||||
transformPrivateToStaticReference(expression) {
|
transformPrivateToStaticReference(expression) {
|
||||||
IrFunctionReferenceImpl(
|
IrFunctionReferenceImpl(
|
||||||
expression.startOffset, expression.endOffset,
|
expression.startOffset, expression.endOffset,
|
||||||
@@ -89,8 +176,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
|||||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||||
super.visitPropertyReference(expression)
|
super.visitPropertyReference(expression)
|
||||||
|
|
||||||
val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) }
|
val staticGetter = expression.getter?.owner?.correspondingStatic
|
||||||
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) }
|
val staticSetter = expression.setter?.owner?.correspondingStatic
|
||||||
|
|
||||||
return if (staticGetter != null || staticSetter != null) {
|
return if (staticGetter != null || staticSetter != null) {
|
||||||
transformPrivateToStaticReference(expression) {
|
transformPrivateToStaticReference(expression) {
|
||||||
@@ -147,88 +234,4 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
|||||||
}
|
}
|
||||||
}, null)
|
}, 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