Forward compatibility hacks for Result.{success, failure}

Don't mangled functions annotated with @JvmName.
Annotate 'Result.success' and 'Result.failure' with @JvmName and
@Suppress("INAPPLICABLE_JVM_NAME").
NB this would require bootstrap.
This commit is contained in:
Dmitry Petrov
2020-06-03 15:55:40 +03:00
parent 8a4521864e
commit 202bbdf8dd
23 changed files with 184 additions and 11 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultAnnotation
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.writeVersionRequirement
@@ -202,7 +203,10 @@ class JvmSerializerExtension @JvmOverloads constructor(
versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement)
}
if (requiresFunctionNameManglingForReturnType(descriptor)) {
if (requiresFunctionNameManglingForReturnType(descriptor) &&
!DescriptorUtils.hasJvmNameAnnotation(descriptor) &&
!requiresFunctionNameManglingForParameterTypes(descriptor)
) {
versionRequirementTable?.writeFunctionNameManglingForReturnTypeRequirement(proto::addVersionRequirement)
}
}
@@ -267,7 +271,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement)
}
if (requiresFunctionNameManglingForReturnType(descriptor)) {
if (!DescriptorUtils.hasJvmNameAnnotation(descriptor) && requiresFunctionNameManglingForReturnType(descriptor)) {
versionRequirementTable?.writeFunctionNameManglingForReturnTypeRequirement(proto::addVersionRequirement)
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
@@ -24,10 +25,13 @@ fun getManglingSuffixBasedOnKotlinSignature(
if (descriptor is ConstructorDescriptor) return null
if (InlineClassDescriptorResolver.isSynthesizedBoxOrUnboxMethod(descriptor)) return null
// Don't mangle functions with '@JvmName' annotation.
// Some stdlib functions ('Result.success', 'Result.failure') are annotated with '@JvmName' as a workaround for forward compatibility.
if (DescriptorUtils.hasJvmNameAnnotation(descriptor)) return null
// If a function accepts inline class parameters, mangle its name.
val actualValueParameterTypes = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
if (requiresFunctionNameManglingForParameterTypes(actualValueParameterTypes)) {
return "-" + md5base64(collectSignatureForMangling(actualValueParameterTypes))
if (requiresFunctionNameManglingForParameterTypes(descriptor)) {
return "-" + md5base64(collectSignatureForMangling(descriptor))
}
// If a class member function returns inline class value, mangle its name.
@@ -42,8 +46,10 @@ fun getManglingSuffixBasedOnKotlinSignature(
return null
}
private fun collectSignatureForMangling(types: List<KotlinType>) =
types.joinToString { getSignatureElementForMangling(it) }
private fun collectSignatureForMangling(descriptor: CallableMemberDescriptor): String {
val types = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
return types.joinToString { getSignatureElementForMangling(it) }
}
private fun getSignatureElementForMangling(type: KotlinType): String = buildString {
val descriptor = type.constructor.declarationDescriptor ?: return ""
@@ -13023,6 +13023,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeMangling.kt");
}
@TestMetadata("noReturnTypeManglingJvmName.kt")
public void testNoReturnTypeManglingJvmName() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeManglingJvmName.kt");
}
@TestMetadata("nullableEqeqNonNull.kt")
public void testNullableEqeqNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nullableEqeqNonNull.kt");
@@ -150,7 +150,7 @@ class JvmNameAnnotationChecker : DeclarationChecker {
if (DescriptorUtils.isOverride(descriptor) || descriptor.isOverridable) {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry))
} else if (descriptor.containingDeclaration.isInlineClassThatRequiresMangling() ||
requiresFunctionNameManglingForParameterTypes(descriptor.valueParameters.map { it.type }) ||
requiresFunctionNameManglingForParameterTypes(descriptor) ||
requiresFunctionNameManglingForReturnType(descriptor)
) {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry))
@@ -0,0 +1,16 @@
// !LANGUAGE: +InlineClasses -MangleClassMembersReturningInlineClasses
// WITH_RUNTIME
// TARGET_BACKEND: JVM
inline class S(val x: String)
class Test {
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("getO")
fun getOK() = S("OK")
}
fun box(): String {
val t = Test()
return t.getOK().x
}
@@ -0,0 +1,20 @@
// !LANGUAGE: +InlineClasses -MangleClassMembersReturningInlineClasses
// WITH_RUNTIME
// TARGET_BACKEND: JVM
// FILE: 1.kt
package test
inline class S(val string: String)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("foo")
inline fun foo() = S("OK")
// FILE: 2.kt
import test.*
fun box() : String =
foo().string
@@ -0,0 +1,20 @@
// !LANGUAGE: +InlineClasses +MangleClassMembersReturningInlineClasses
// WITH_RUNTIME
// TARGET_BACKEND: JVM
// FILE: 1.kt
package test
inline class S(val string: String)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("foo")
inline fun foo() = S("OK")
// FILE: 2.kt
import test.*
fun box() : String =
foo().string
@@ -0,0 +1,21 @@
// WITH_RUNTIME
inline class IC(val x: Int)
class C {
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("test")
fun test() = IC(42)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("differentName")
fun test2() = IC(42)
}
fun call1() = C().test()
fun call2() = C().test2()
// 1 public final test\(\)I
// 1 INVOKEVIRTUAL C.test \(\)I
// 1 public final differentName\(\)I
// 1 INVOKEVIRTUAL C.differentName \(\)I
@@ -5,6 +5,10 @@ inline class IC(val x: Int)
class C {
fun returnsInlineClassType(): IC = IC(42)
val propertyOfInlineClassType: IC get() = IC(42)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("returnsInlineClassTypeJvmName")
fun returnsInlineClassTypeJvmName(): IC = IC(42)
}
fun returnsInlineClassType(): IC = IC(42)
@@ -14238,6 +14238,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeMangling.kt");
}
@TestMetadata("noReturnTypeManglingJvmName.kt")
public void testNoReturnTypeManglingJvmName() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeManglingJvmName.kt");
}
@TestMetadata("nullableEqeqNonNull.kt")
public void testNullableEqeqNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nullableEqeqNonNull.kt");
@@ -1896,6 +1896,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFun.kt");
}
@TestMetadata("noReturnTypeManglingFunJvmName.kt")
public void testNoReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("noReturnTypeManglingVal.kt")
public void testNoReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingVal.kt");
@@ -1906,6 +1911,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFun.kt");
}
@TestMetadata("withReturnTypeManglingFunJvmName.kt")
public void testWithReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("withReturnTypeManglingVal.kt")
public void testWithReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingVal.kt");
@@ -2951,6 +2951,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingUnboxingInAccessorsForDelegatedPropertyWithInlineClassDelegate.kt");
}
@TestMetadata("noManglingForFunctionsWithJvmName.kt")
public void testNoManglingForFunctionsWithJvmName() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noManglingForFunctionsWithJvmName.kt");
}
@TestMetadata("noReturnTypeMangling.kt")
public void testNoReturnTypeMangling() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noReturnTypeMangling.kt");
@@ -1896,6 +1896,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFun.kt");
}
@TestMetadata("noReturnTypeManglingFunJvmName.kt")
public void testNoReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("noReturnTypeManglingVal.kt")
public void testNoReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingVal.kt");
@@ -1906,6 +1911,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFun.kt");
}
@TestMetadata("withReturnTypeManglingFunJvmName.kt")
public void testWithReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("withReturnTypeManglingVal.kt")
public void testWithReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingVal.kt");
@@ -14243,6 +14243,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeMangling.kt");
}
@TestMetadata("noReturnTypeManglingJvmName.kt")
public void testNoReturnTypeManglingJvmName() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeManglingJvmName.kt");
}
@TestMetadata("nullableEqeqNonNull.kt")
public void testNullableEqeqNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nullableEqeqNonNull.kt");
@@ -13023,6 +13023,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeMangling.kt");
}
@TestMetadata("noReturnTypeManglingJvmName.kt")
public void testNoReturnTypeManglingJvmName() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noReturnTypeManglingJvmName.kt");
}
@TestMetadata("nullableEqeqNonNull.kt")
public void testNullableEqeqNonNull() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nullableEqeqNonNull.kt");
@@ -1896,6 +1896,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFun.kt");
}
@TestMetadata("noReturnTypeManglingFunJvmName.kt")
public void testNoReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("noReturnTypeManglingVal.kt")
public void testNoReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingVal.kt");
@@ -1906,6 +1911,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFun.kt");
}
@TestMetadata("withReturnTypeManglingFunJvmName.kt")
public void testWithReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("withReturnTypeManglingVal.kt")
public void testWithReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingVal.kt");
@@ -3036,6 +3036,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noBoxingUnboxingInAccessorsForDelegatedPropertyWithInlineClassDelegate.kt");
}
@TestMetadata("noManglingForFunctionsWithJvmName.kt")
public void testNoManglingForFunctionsWithJvmName() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noManglingForFunctionsWithJvmName.kt");
}
@TestMetadata("noReturnTypeMangling.kt")
public void testNoReturnTypeMangling() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noReturnTypeMangling.kt");
@@ -1896,6 +1896,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFun.kt");
}
@TestMetadata("noReturnTypeManglingFunJvmName.kt")
public void testNoReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("noReturnTypeManglingVal.kt")
public void testNoReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/noReturnTypeManglingVal.kt");
@@ -1906,6 +1911,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFun.kt");
}
@TestMetadata("withReturnTypeManglingFunJvmName.kt")
public void testWithReturnTypeManglingFunJvmName() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingFunJvmName.kt");
}
@TestMetadata("withReturnTypeManglingVal.kt")
public void testWithReturnTypeManglingVal() throws Exception {
runTest("compiler/testData/codegen/boxInline/inlineClasses/withReturnTypeManglingVal.kt");
@@ -145,6 +145,7 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() {
doTest(
VersionRequirement.Version(1, 3, 0), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null,
fqNamesWithRequirements = listOf(
"test.C.returnsInlineClassTypeJvmName",
"test.returnsInlineClassType",
"test.propertyOfInlineClassType"
),
@@ -24,8 +24,10 @@ fun shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor: Callabl
return constructorDescriptor.valueParameters.any { it.type.requiresFunctionNameManglingInParameterTypes() }
}
fun requiresFunctionNameManglingForParameterTypes(valueParameterTypes: List<KotlinType>): Boolean {
return valueParameterTypes.any { it.requiresFunctionNameManglingInParameterTypes() }
fun requiresFunctionNameManglingForParameterTypes(descriptor: CallableMemberDescriptor): Boolean {
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
return extensionReceiverType != null && extensionReceiverType.requiresFunctionNameManglingInParameterTypes() ||
descriptor.valueParameters.any { it.type.requiresFunctionNameManglingInParameterTypes() }
}
// NB functions returning all inline classes (including our special 'kotlin.Result') should be mangled.
@@ -569,6 +569,10 @@ public class DescriptorUtils {
return annotated.getAnnotations().findAnnotation(JVM_NAME);
}
public static boolean hasJvmNameAnnotation(@NotNull Annotated annotated) {
return findJvmNameAnnotation(annotated) != null;
}
@NotNull
public static SourceFile getContainingSourceFile(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof PropertySetterDescriptor) {
+1 -1
View File
@@ -14,4 +14,4 @@ suspend fun bar(): Unit {
println(a + b)
}
// LINES: 38 4 4 4 7 5 5 44 44 5 89 44 5 5 6 4 4 4 9 15 9 9 9 * 9 15 10 10 11 11 11 11 11 * 11 12 12 13 13 13 13 13 13 13 14 14 * 9 15 9 9 9 9
// LINES: 38 4 4 4 7 5 5 44 44 5 92 44 5 5 6 4 4 4 9 15 9 9 9 * 9 15 10 10 11 11 11 11 11 * 11 12 12 13 13 13 13 13 13 13 14 14 * 9 15 9 9 9 9
@@ -10,6 +10,7 @@ package kotlin
import kotlin.contracts.*
import kotlin.internal.InlineOnly
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName
/**
* A discriminated union that encapsulates a successful outcome with a value of type [T]
@@ -84,14 +85,18 @@ public inline class Result<out T> @PublishedApi internal constructor(
/**
* Returns an instance that encapsulates the given [value] as successful value.
*/
@Suppress("INAPPLICABLE_JVM_NAME")
@InlineOnly
@JvmName("success")
public inline fun <T> success(value: T): Result<T> =
Result(value)
/**
* Returns an instance that encapsulates the given [Throwable] [exception] as failure.
*/
@Suppress("INAPPLICABLE_JVM_NAME")
@InlineOnly
@JvmName("failure")
public inline fun <T> failure(exception: Throwable): Result<T> =
Result(createFailure(exception))
}