From 0b49dc2248c29344901ea8b6e5fe7c45fa8d653b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 1 Nov 2022 00:07:58 +0100 Subject: [PATCH] Fix binary compatibility for inlined local delegated properies #KT-54650 Fixed --- .../common/lower/LocalDeclarationsLowering.kt | 22 ++++++++++++++----- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 1 + .../localDelegatedProperty.kt | 10 +++++++++ .../localDelegatedProperty.txt | 20 +++++++++++++++++ .../localDelegatedProperty_ir.txt | 12 ++++++++++ .../codegen/BytecodeListingTestGenerated.java | 6 +++++ .../IrBytecodeListingTestGenerated.java | 6 +++++ 7 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt create mode 100644 compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.txt create mode 100644 compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty_ir.txt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index dce0a538485c8..edd2d97d0177c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -8,13 +8,14 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString -import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.lower.inline.isInlineParameter import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter @@ -25,7 +26,9 @@ import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl -import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.transformStatement +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -71,6 +74,7 @@ class LocalDeclarationsLowering( val localNameSanitizer: (String) -> String = { it }, val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT, val suggestUniqueNames: Boolean = true, // When `true` appends a `$#index` suffix to lifted declaration names + val compatibilityModeForInlinedLocalDelegatedPropertyAccessors: Boolean = false, // Keep old names because of KT-49030 val forceFieldsForInlineCaptures: Boolean = false, // See `LocalClassContext` private val postLocalDeclarationLoweringCallback: ((IntermediateDatastructures) -> Unit)? = null ) : @@ -589,8 +593,16 @@ class LocalDeclarationsLowering( val declarationName = localNameSanitizer(declaration.name.asString()) localFunctions[declaration]?.let { val baseName = if (declaration.name.isSpecial) "lambda" else declarationName - if (it.index >= 0) - return if (suggestUniqueNames) "$baseName\$${it.index}" else baseName + if (it.index >= 0) { + if (!suggestUniqueNames) return baseName + + val separator = if ( + compatibilityModeForInlinedLocalDelegatedPropertyAccessors && + declaration.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR && + container is IrFunction && container.isInline + ) "-" else "$" + return "$baseName$separator${it.index}" + } } return declarationName diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 8356fed4b8fdf..79bffff41d708 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -138,6 +138,7 @@ internal val localDeclarationsPhase = makeIrFilePhase( private fun scopedVisibility(inInlineFunctionScope: Boolean): DescriptorVisibility = if (inInlineFunctionScope) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY }, + compatibilityModeForInlinedLocalDelegatedPropertyAccessors = true, forceFieldsForInlineCaptures = true, postLocalDeclarationLoweringCallback = context.localDeclarationsLoweringData?.let { { data -> diff --git a/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt new file mode 100644 index 0000000000000..fe9991be6f043 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt @@ -0,0 +1,10 @@ +// This test checks that we use the `...$lambda-0` method name, instead of `...$lambda$0`, for extracted accessors of local delegated properties. +// It's important to keep these names until we fix the binary compatibility issue KT-49030. + +operator fun String.getValue(thisRef: Any?, prop: Any?): String = this +operator fun String.setValue(thisRef: Any?, prop: Any?, value: String) {} + +inline fun foo(): String { + var x by "OK" + return x +} diff --git a/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.txt b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.txt new file mode 100644 index 0000000000000..076966af77dc9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.txt @@ -0,0 +1,20 @@ +@kotlin.Metadata +public final class LocalDelegatedPropertyKt$foo$x$1 { + // source: 'localDelegatedProperty.kt' + public final static field INSTANCE: kotlin.reflect.KMutableProperty0 + static method (): void + method (): void + public method getName(): java.lang.String + public method getOwner(): kotlin.reflect.KDeclarationContainer + public method getSignature(): java.lang.String +} + +@kotlin.Metadata +public final class LocalDelegatedPropertyKt { + // source: 'localDelegatedProperty.kt' + synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[] + static method (): void + public final static @org.jetbrains.annotations.NotNull method foo(): java.lang.String + public final static @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.Nullable p2: java.lang.Object): java.lang.String + public final static method setValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.Nullable p2: java.lang.Object, @org.jetbrains.annotations.NotNull p3: java.lang.String): void +} diff --git a/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty_ir.txt b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty_ir.txt new file mode 100644 index 0000000000000..9220aaa916f82 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty_ir.txt @@ -0,0 +1,12 @@ +@kotlin.Metadata +public final class LocalDelegatedPropertyKt { + // source: 'localDelegatedProperty.kt' + synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[] + static method (): void + public synthetic final static method access$foo$lambda-0(p0: java.lang.String): java.lang.String + private final static method foo$lambda-0(p0: java.lang.String): java.lang.String + private final static method foo$lambda-1(p0: java.lang.String, p1: java.lang.String): void + public final static @org.jetbrains.annotations.NotNull method foo(): java.lang.String + public final static @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.Nullable p2: java.lang.Object): java.lang.String + public final static method setValue(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.Nullable p1: java.lang.Object, @org.jetbrains.annotations.Nullable p2: java.lang.Object, @org.jetbrains.annotations.NotNull p3: java.lang.String): void +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java index 0987f13011c63..0a7994503d0af 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeListingTestGenerated.java @@ -1037,6 +1037,12 @@ public void testDelegateMethodIsNonOverridable() throws Exception { public void testDelegatedPropertiesInCompanionObject() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/delegatedProperty/delegatedPropertiesInCompanionObject.kt"); } + + @Test + @TestMetadata("localDelegatedProperty.kt") + public void testLocalDelegatedProperty() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java index 5d9f39ba192e6..6493459a3ee88 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeListingTestGenerated.java @@ -1133,6 +1133,12 @@ public void testDelegateMethodIsNonOverridable() throws Exception { public void testDelegatedPropertiesInCompanionObject() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/delegatedProperty/delegatedPropertiesInCompanionObject.kt"); } + + @Test + @TestMetadata("localDelegatedProperty.kt") + public void testLocalDelegatedProperty() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/delegatedProperty/localDelegatedProperty.kt"); + } } @Nested