[JS IR] Make PrivateMembersLowering global to handle inlined private references correctly

- Fixes [KT-33334]
This commit is contained in:
Roman Artemev
2019-11-20 21:34:25 +03:00
committed by romanart
parent 9946feb66c
commit c5e25a0382
5 changed files with 114 additions and 52 deletions
@@ -51,6 +51,8 @@ class JsIrBackendContext(
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>() override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
override val lateinitNullableFields = mutableMapOf<IrField, IrField>() override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
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
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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
@@ -33,13 +33,11 @@ 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) : FileLoweringPass {
private val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>() private val memberMap = context.memberMap
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
transformPrivateDeclarations(irFile) transformPrivateDeclarations(irFile)
transformPrivateUseSites(irFile) transformPrivateUseSites(irFile)
memberMap.clear()
} }
private fun transformPrivateDeclarations(irFile: IrFile) { private fun transformPrivateDeclarations(irFile: IrFile) {
@@ -49,7 +47,6 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
declaration.declarations.transformFlat { declaration.declarations.transformFlat {
when (it) { when (it) {
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction -> is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction ->
memberMap[it.symbol] = staticFunction
listOf(staticFunction) listOf(staticFunction)
} }
is IrProperty -> listOf(it.apply { is IrProperty -> listOf(it.apply {
@@ -69,7 +66,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression) super.visitCall(expression)
return memberMap[expression.symbol]?.let { return getOrPutStaticFunction(expression.symbol)?.let {
transformPrivateToStaticCall(expression, it) transformPrivateToStaticCall(expression, it)
} ?: expression } ?: expression
} }
@@ -77,7 +74,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 memberMap[expression.symbol]?.let { return getOrPutStaticFunction(expression.symbol)?.let {
transformPrivateToStaticReference(expression) { transformPrivateToStaticReference(expression) {
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
@@ -92,7 +89,10 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression { override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
super.visitPropertyReference(expression) super.visitPropertyReference(expression)
return if (expression.getter in memberMap || expression.setter in memberMap) { val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) }
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) }
return if (staticGetter != null || staticSetter != null) {
transformPrivateToStaticReference(expression) { transformPrivateToStaticReference(expression) {
IrPropertyReferenceImpl( IrPropertyReferenceImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
@@ -100,8 +100,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
expression.symbol, // TODO remap property symbol based on remapped getter/setter? expression.symbol, // TODO remap property symbol based on remapped getter/setter?
expression.typeArgumentsCount, expression.typeArgumentsCount,
expression.field, expression.field,
memberMap[expression.getter]?.symbol ?: expression.getter, staticGetter?.symbol ?: expression.getter,
memberMap[expression.setter]?.symbol ?: expression.setter, staticSetter?.symbol ?: expression.setter,
expression.origin expression.origin
) )
} }
@@ -127,6 +127,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
return newExpression return newExpression
} }
private fun transformPrivateToStaticReference( private fun transformPrivateToStaticReference(
expression: IrCallableReference, expression: IrCallableReference,
builder: () -> IrCallableReference builder: () -> IrCallableReference
@@ -147,28 +148,11 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
}, null) }, null)
} }
private fun transformAccessor(accessor: IrSimpleFunction) = private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
transformMemberToStaticFunction(accessor)?.also { memberMap[accessor.symbol] = it } ?: accessor
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? { private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null val staticFunction = getOrPutStaticFunction(function.symbol) ?: 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
).also {
descriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
}
}
// Detach old function from corresponding property // Detach old function from corresponding property
val correspondingProperty = function.correspondingPropertySymbol?.owner val correspondingProperty = function.correspondingPropertySymbol?.owner
@@ -179,29 +163,6 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
} }
} }
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,
false,
false
).also {
thisDesc.bind(it)
it.parent = staticFunction
}
staticFunction.valueParameters += function.valueParameters.map { it.copyTo(staticFunction, index = it.index + 1) }
val oldParameters = val oldParameters =
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
@@ -220,4 +181,53 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
return staticFunction 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
).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
}
}
} }
@@ -4249,6 +4249,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/inlineMultiFile/lambdaInLambdaNoInline.kt"); runTest("js/js.translator/testData/box/inlineMultiFile/lambdaInLambdaNoInline.kt");
} }
@TestMetadata("privateVarFromInline.kt")
public void testPrivateVarFromInline() throws Exception {
runTest("js/js.translator/testData/box/inlineMultiFile/privateVarFromInline.kt");
}
@TestMetadata("regeneratedLambdaName.kt") @TestMetadata("regeneratedLambdaName.kt")
public void testRegeneratedLambdaName() throws Exception { public void testRegeneratedLambdaName() throws Exception {
runTest("js/js.translator/testData/box/inlineMultiFile/regeneratedLambdaName.kt"); runTest("js/js.translator/testData/box/inlineMultiFile/regeneratedLambdaName.kt");
@@ -4264,6 +4264,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/inlineMultiFile/lambdaInLambdaNoInline.kt"); runTest("js/js.translator/testData/box/inlineMultiFile/lambdaInLambdaNoInline.kt");
} }
@TestMetadata("privateVarFromInline.kt")
public void testPrivateVarFromInline() throws Exception {
runTest("js/js.translator/testData/box/inlineMultiFile/privateVarFromInline.kt");
}
@TestMetadata("regeneratedLambdaName.kt") @TestMetadata("regeneratedLambdaName.kt")
public void testRegeneratedLambdaName() throws Exception { public void testRegeneratedLambdaName() throws Exception {
runTest("js/js.translator/testData/box/inlineMultiFile/regeneratedLambdaName.kt"); runTest("js/js.translator/testData/box/inlineMultiFile/regeneratedLambdaName.kt");
@@ -0,0 +1,40 @@
// FILE: f.kt
package foo
/**
* KT-33334
*/
internal fun foo(c: C) = c.getter()
internal fun bar(c: C) { c.setter("OK") }
// FILE: c.kt
package foo
var log = ""
internal class C {
private var tokenPosition: String = "FAIL"
get() { logg("G"); return field }
set(value) { logg("S"); field = value }
private fun logg(s: String) { log += s }
internal inline fun setter(s: String) { tokenPosition = s }
internal inline fun getter(): String = tokenPosition
}
// FILE: m.kt
package foo
fun box(): String {
val c = C()
bar(c)
val r = foo(c)
if (log != "SG") return "FAIL1: $log"
return r
}