JVM IR: Fix corresponding properties in inline classes
This commit is contained in:
committed by
Alexander Udalov
parent
c41e71b1c5
commit
497df0922a
Generated
+5
@@ -12958,6 +12958,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
+58
-23
@@ -9,20 +9,26 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.MethodSignatureMapper
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.inlineClassFieldName
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
@@ -37,6 +43,8 @@ import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -65,9 +73,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
}
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
}
|
||||
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
|
||||
|
||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||
// The arguments to the primary constructor are in scope in the initializers of IrFields.
|
||||
@@ -117,17 +123,6 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction) {
|
||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||
irExprBody(irCall(target).apply {
|
||||
passTypeArgumentsFrom(source)
|
||||
for ((parameter, newParameter) in source.explicitParameters.zip(target.explicitParameters)) {
|
||||
putArgument(newParameter, irGet(parameter))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
replacement.valueParameters.forEach { it.transformChildrenVoid() }
|
||||
replacement.body = function.body?.transform(this, null)?.patchDeclarationParents(replacement)
|
||||
@@ -137,15 +132,26 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null)
|
||||
return listOf(replacement)
|
||||
|
||||
// If the original function has value parameters which need mangling we still need to replace
|
||||
// it with a mangled version.
|
||||
val bridgeFunction = if (!function.isFakeOverride && function.fullValueParameterList.any { it.type.requiresMangling }) {
|
||||
context.inlineClassReplacements.createMethodReplacement(function)
|
||||
} else {
|
||||
// Update the overridden symbols to point to their inline class replacements
|
||||
function.overriddenSymbols = replacement.overriddenSymbols
|
||||
function
|
||||
}
|
||||
val bridgeFunction = createBridgeDeclaration(
|
||||
function,
|
||||
when {
|
||||
// If the original function has value parameters which need mangling we still need to replace
|
||||
// it with a mangled version.
|
||||
!function.isFakeOverride && function.fullValueParameterList.any { it.type.requiresMangling } ->
|
||||
replacement.name
|
||||
// Since we remove the corresponding property symbol from the bridge we need to resolve getter/setter
|
||||
// names at this point.
|
||||
replacement.isGetter ->
|
||||
Name.identifier(JvmAbi.getterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
replacement.isSetter ->
|
||||
Name.identifier(JvmAbi.setterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
|
||||
else ->
|
||||
function.name
|
||||
}
|
||||
)
|
||||
|
||||
// Update the overridden symbols to point to their inline class replacements
|
||||
bridgeFunction.overriddenSymbols = replacement.overriddenSymbols
|
||||
|
||||
// Replace the function body with a wrapper
|
||||
if (!bridgeFunction.isFakeOverride || !bridgeFunction.parentAsClass.isInline) {
|
||||
@@ -158,6 +164,35 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
return listOf(replacement, bridgeFunction)
|
||||
}
|
||||
|
||||
// We may need to add a bridge method for inline class methods with static replacements. Ideally, we'd do this in BridgeLowering,
|
||||
// but unfortunately this is a special case in the old backend. The bridge method is not marked as such and does not follow the normal
|
||||
// visibility rules for bridge methods.
|
||||
private fun createBridgeDeclaration(source: IrSimpleFunction, mangledName: Name) =
|
||||
buildFun {
|
||||
updateFrom(source)
|
||||
name = mangledName
|
||||
returnType = source.returnType
|
||||
}.apply {
|
||||
copyParameterDeclarationsFrom(source)
|
||||
annotations += source.annotations
|
||||
parent = source.parent
|
||||
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
|
||||
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
|
||||
// a continuation class.
|
||||
copyAttributes(source)
|
||||
}
|
||||
|
||||
private fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction) {
|
||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||
irExprBody(irCall(target).apply {
|
||||
passTypeArgumentsFrom(source)
|
||||
for ((parameter, newParameter) in source.explicitParameters.zip(target.explicitParameters)) {
|
||||
putArgument(newParameter, irGet(parameter))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary constructors for boxed types get translated to static functions returning
|
||||
// unboxed arguments. We remove the original constructor.
|
||||
private fun transformConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
|
||||
+44
-25
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -32,6 +34,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
*/
|
||||
class MemoizedInlineClassReplacements {
|
||||
private val storageManager = LockBasedStorageManager("inline-class-replacements")
|
||||
private val propertyMap = mutableMapOf<IrPropertySymbol, IrProperty>()
|
||||
|
||||
/**
|
||||
* Get a replacement for a function or a constructor.
|
||||
@@ -124,7 +127,7 @@ class MemoizedInlineClassReplacements {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
||||
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
||||
buildReplacement(function, function.origin) {
|
||||
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
||||
val newValueParameters = ArrayList<IrValueParameter>()
|
||||
@@ -176,33 +179,49 @@ class MemoizedInlineClassReplacements {
|
||||
replacementOrigin: IrDeclarationOrigin,
|
||||
noFakeOverride: Boolean = false,
|
||||
body: IrFunctionImpl.() -> Unit
|
||||
) =
|
||||
buildFunWithDescriptorForInlining(function.descriptor) {
|
||||
updateFrom(function)
|
||||
origin = if (function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER) {
|
||||
JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD
|
||||
} else {
|
||||
replacementOrigin
|
||||
}
|
||||
if (noFakeOverride) {
|
||||
isFakeOverride = false
|
||||
}
|
||||
name = mangledNameFor(function)
|
||||
returnType = function.returnType
|
||||
}.apply {
|
||||
parent = function.parent
|
||||
annotations += function.annotations
|
||||
copyTypeParameters(function.allTypeParameters)
|
||||
metadata = function.metadata
|
||||
function.safeAs<IrFunctionBase<*>>()?.metadata = null
|
||||
) = buildFunWithDescriptorForInlining(function.descriptor) {
|
||||
updateFrom(function)
|
||||
origin = if (function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER) {
|
||||
JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD
|
||||
} else {
|
||||
replacementOrigin
|
||||
}
|
||||
if (noFakeOverride) {
|
||||
isFakeOverride = false
|
||||
}
|
||||
name = mangledNameFor(function)
|
||||
returnType = function.returnType
|
||||
}.apply {
|
||||
parent = function.parent
|
||||
annotations += function.annotations
|
||||
copyTypeParameters(function.allTypeParameters)
|
||||
metadata = function.metadata
|
||||
function.safeAs<IrFunctionBase<*>>()?.metadata = null
|
||||
|
||||
if (function is IrSimpleFunction) {
|
||||
correspondingPropertySymbol = function.correspondingPropertySymbol
|
||||
overriddenSymbols = function.overriddenSymbols.map {
|
||||
getReplacementFunction(it.owner)?.symbol ?: it
|
||||
if (function is IrSimpleFunction) {
|
||||
val propertySymbol = function.correspondingPropertySymbol
|
||||
if (propertySymbol != null) {
|
||||
val property = propertyMap.getOrPut(propertySymbol) {
|
||||
buildProperty(propertySymbol.descriptor) {
|
||||
name = propertySymbol.owner.name
|
||||
updateFrom(propertySymbol.owner)
|
||||
}.apply {
|
||||
parent = propertySymbol.owner.parent
|
||||
}
|
||||
}
|
||||
correspondingPropertySymbol = property.symbol
|
||||
when (function) {
|
||||
propertySymbol.owner.getter -> property.getter = this
|
||||
propertySymbol.owner.setter -> property.setter = this
|
||||
else -> error("Orphaned property getter/setter: ${function.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
body()
|
||||
overriddenSymbols = function.overriddenSymbols.map {
|
||||
getReplacementFunction(it.owner)?.symbol ?: it
|
||||
}
|
||||
}
|
||||
|
||||
body()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// FILE: 1.kt
|
||||
|
||||
inline class A(val x: String)
|
||||
|
||||
fun accessProperty(y: B): A {
|
||||
y.a = A("OK")
|
||||
return y.a
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
|
||||
class B(var a: A)
|
||||
|
||||
fun box(): String = accessProperty(B(A("Fail"))).x
|
||||
+5
@@ -14173,6 +14173,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
+5
@@ -14178,6 +14178,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
+5
@@ -12958,6 +12958,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
Generated
+5
@@ -11148,6 +11148,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
+5
@@ -11213,6 +11213,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/passInlineClassWithSpreadOperatorToVarargs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyLoweringOrder.kt")
|
||||
public void testPropertyLoweringOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/propertyLoweringOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referToPropertyInCompanionObjectOfInlineClass.kt")
|
||||
public void testReferToPropertyInCompanionObjectOfInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/referToPropertyInCompanionObjectOfInlineClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user