JVM_IR: do not move receivers on functions with inline class parameters
^KT-48993 Fixed
This commit is contained in:
+6
@@ -19488,6 +19488,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt48993.kt")
|
||||||
|
public void testKt48993() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("mangledDefaultParameterFunction.kt")
|
@TestMetadata("mangledDefaultParameterFunction.kt")
|
||||||
public void testMangledDefaultParameterFunction() throws Exception {
|
public void testMangledDefaultParameterFunction() throws Exception {
|
||||||
|
|||||||
+7
-10
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||||
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod
|
import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.codegen.extensionReceiverName
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId
|
import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||||
@@ -81,10 +82,7 @@ class MemoizedInlineClassReplacements(
|
|||||||
|
|
||||||
// Otherwise, mangle functions with mangled parameters, ignoring constructors
|
// Otherwise, mangle functions with mangled parameters, ignoring constructors
|
||||||
it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
|
it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
|
||||||
if (it.dispatchReceiverParameter != null)
|
createMethodReplacement(it)
|
||||||
createMethodReplacement(it)
|
|
||||||
else
|
|
||||||
createStaticReplacement(it)
|
|
||||||
|
|
||||||
else ->
|
else ->
|
||||||
null
|
null
|
||||||
@@ -182,9 +180,11 @@ class MemoizedInlineClassReplacements(
|
|||||||
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
||||||
buildReplacement(function, function.origin) {
|
buildReplacement(function, function.origin) {
|
||||||
originalFunctionForMethodReplacement[this] = function
|
originalFunctionForMethodReplacement[this] = function
|
||||||
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
|
||||||
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
|
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
|
||||||
extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this, index = -1, name = Name.identifier("\$receiver"))
|
extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(
|
||||||
|
// The function's name will be mangled, so preserve the old receiver name.
|
||||||
|
this, index = -1, name = Name.identifier(function.extensionReceiverName(context.state))
|
||||||
|
)
|
||||||
valueParameters = function.valueParameters.mapIndexed { index, parameter ->
|
valueParameters = function.valueParameters.mapIndexed { index, parameter ->
|
||||||
parameter.copyTo(this, index = index, defaultValue = null).also {
|
parameter.copyTo(this, index = index, defaultValue = null).also {
|
||||||
// Assuming that constructors and non-override functions are always replaced with the unboxed
|
// Assuming that constructors and non-override functions are always replaced with the unboxed
|
||||||
@@ -207,11 +207,8 @@ class MemoizedInlineClassReplacements(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
function.extensionReceiverParameter?.let {
|
function.extensionReceiverParameter?.let {
|
||||||
val baseName =
|
|
||||||
(function as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name?.asStringStripSpecialMarkers()
|
|
||||||
?: function.name
|
|
||||||
newValueParameters += it.copyTo(
|
newValueParameters += it.copyTo(
|
||||||
this, index = newValueParameters.size, name = Name.identifier("\$this\$$baseName"),
|
this, index = newValueParameters.size, name = Name.identifier(function.extensionReceiverName(context.state)),
|
||||||
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-24
@@ -69,7 +69,7 @@ class FunctionCodegen(private val irFunction: IrFunction, private val classCodeg
|
|||||||
val methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode)
|
val methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode)
|
||||||
|
|
||||||
if (context.state.generateParametersMetadata && !isSynthetic) {
|
if (context.state.generateParametersMetadata && !isSynthetic) {
|
||||||
generateParameterNames(irFunction, methodVisitor, signature, context.state)
|
generateParameterNames(irFunction, methodVisitor, context.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irFunction.origin !in methodOriginsWithoutAnnotations) {
|
if (irFunction.origin !in methodOriginsWithoutAnnotations) {
|
||||||
@@ -329,23 +329,16 @@ private fun IrValueParameter.isSyntheticMarkerParameter(): Boolean =
|
|||||||
origin == IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER ||
|
origin == IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER ||
|
||||||
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_MARKER_PARAMETER
|
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_MARKER_PARAMETER
|
||||||
|
|
||||||
private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jvmSignature: JvmMethodSignature, state: GenerationState) {
|
private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, state: GenerationState) {
|
||||||
val iterator = irFunction.valueParameters.iterator()
|
irFunction.extensionReceiverParameter?.let {
|
||||||
for (parameterSignature in jvmSignature.valueParameters) {
|
mv.visitParameter(irFunction.extensionReceiverName(state), Opcodes.ACC_MANDATED)
|
||||||
val irParameter = when (parameterSignature.kind) {
|
}
|
||||||
JvmMethodParameterKind.RECEIVER -> irFunction.extensionReceiverParameter!!
|
for (irParameter in irFunction.valueParameters) {
|
||||||
else -> iterator.next()
|
|
||||||
}
|
|
||||||
val name = when (parameterSignature.kind) {
|
|
||||||
JvmMethodParameterKind.RECEIVER -> getNameForReceiverParameter(irFunction, state)
|
|
||||||
else -> irParameter.name.asString()
|
|
||||||
}
|
|
||||||
// A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared
|
// A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared
|
||||||
// explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).
|
// explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).
|
||||||
// A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter
|
// A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter
|
||||||
// declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1).
|
// declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1).
|
||||||
val access = when {
|
val access = when {
|
||||||
irParameter == irFunction.extensionReceiverParameter -> Opcodes.ACC_MANDATED
|
|
||||||
irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED
|
irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED
|
||||||
// TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected
|
// TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected
|
||||||
// to generate LVT entries for them)
|
// to generate LVT entries for them)
|
||||||
@@ -356,24 +349,21 @@ private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jv
|
|||||||
irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC
|
irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
mv.visitParameter(name, access)
|
mv.visitParameter(irParameter.name.asString(), access)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNameForReceiverParameter(irFunction: IrFunction, state: GenerationState): String {
|
internal fun IrFunction.extensionReceiverName(state: GenerationState): String {
|
||||||
if (!state.languageVersionSettings.supportsFeature(LanguageFeature.NewCapturedReceiverFieldNamingConvention)) {
|
if (!state.languageVersionSettings.supportsFeature(LanguageFeature.NewCapturedReceiverFieldNamingConvention)) {
|
||||||
return AsmUtil.RECEIVER_PARAMETER_NAME
|
return AsmUtil.RECEIVER_PARAMETER_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current codegen never touches CALL_LABEL_FOR_LAMBDA_ARGUMENT
|
extensionReceiverParameter?.let {
|
||||||
// if (irFunction is IrSimpleFunction) {
|
if (it.name.asString().startsWith(AsmUtil.LABELED_THIS_PARAMETER)) {
|
||||||
// val labelName = bindingContext.get(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, irFunction.descriptor)
|
return it.name.asString()
|
||||||
// if (labelName != null) {
|
}
|
||||||
// return getLabeledThisName(labelName, prefix, defaultName)
|
}
|
||||||
// }
|
val callableName = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name ?: name
|
||||||
// }
|
|
||||||
|
|
||||||
val callableName = irFunction.safeAs<IrSimpleFunction>()?.correspondingPropertySymbol?.owner?.name ?: irFunction.name
|
|
||||||
return if (callableName.isSpecial || !Name.isValidIdentifier(callableName.asString()))
|
return if (callableName.isSpecial || !Name.isValidIdentifier(callableName.asString()))
|
||||||
AsmUtil.RECEIVER_PARAMETER_NAME
|
AsmUtil.RECEIVER_PARAMETER_NAME
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// FILE: 1.kt
|
||||||
|
inline class C(val x: String)
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
@file:JvmMultifileClass
|
||||||
|
@file:JvmName("Multifile")
|
||||||
|
|
||||||
|
private var result: String? = null
|
||||||
|
|
||||||
|
var String.k: C
|
||||||
|
get() = C(this + result!!)
|
||||||
|
set(value) { result = value.x }
|
||||||
|
|
||||||
|
// FILE: 3.kt
|
||||||
|
fun box(): String {
|
||||||
|
"".k = C("K")
|
||||||
|
return "O".k.x
|
||||||
|
}
|
||||||
+6
@@ -19356,6 +19356,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt48993.kt")
|
||||||
|
public void testKt48993() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("mangledDefaultParameterFunction.kt")
|
@TestMetadata("mangledDefaultParameterFunction.kt")
|
||||||
public void testMangledDefaultParameterFunction() throws Exception {
|
public void testMangledDefaultParameterFunction() throws Exception {
|
||||||
|
|||||||
+6
@@ -19488,6 +19488,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt48993.kt")
|
||||||
|
public void testKt48993() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("mangledDefaultParameterFunction.kt")
|
@TestMetadata("mangledDefaultParameterFunction.kt")
|
||||||
public void testMangledDefaultParameterFunction() throws Exception {
|
public void testMangledDefaultParameterFunction() throws Exception {
|
||||||
|
|||||||
+5
@@ -16078,6 +16078,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt48993.kt")
|
||||||
|
public void testKt48993() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("mangledDefaultParameterFunction.kt")
|
@TestMetadata("mangledDefaultParameterFunction.kt")
|
||||||
public void testMangledDefaultParameterFunction() throws Exception {
|
public void testMangledDefaultParameterFunction() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user