diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 38d12ebb8bd..52461e77bf2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -24,7 +25,9 @@ import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.isInlineOnly +import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.types.KotlinType @@ -629,8 +632,7 @@ abstract class InlineCodegen( ?: throw IllegalStateException("Couldn't find declaration file for $containerId") } - val methodNode = - getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, AsmUtil.asmTypeByClassId(containerId)) ?: return null + val methodNode = getMethodNodeInner(containerId, bytes, asmMethod, callableDescriptor) ?: return null // KLUDGE: Inline suspend function built with compiler version less than 1.1.4/1.2-M1 did not contain proper // before/after suspension point marks, so we detect those functions here and insert the corresponding marks @@ -641,6 +643,28 @@ abstract class InlineCodegen( return methodNode } + private fun getMethodNodeInner( + containerId: ClassId, + bytes: ByteArray, + asmMethod: Method, + callableDescriptor: CallableMemberDescriptor + ): SMAPAndMethodNode? { + val classType = AsmUtil.asmTypeByClassId(containerId) + var methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classType) + if (methodNode == null && requiresFunctionNameManglingForReturnType(callableDescriptor)) { + val nameWithoutManglingSuffix = asmMethod.name.stripManglingSuffixOrNull() + if (nameWithoutManglingSuffix != null) { + methodNode = getMethodNode(bytes, nameWithoutManglingSuffix, asmMethod.descriptor, classType) + } + } + return methodNode + } + + private fun String.stripManglingSuffixOrNull(): String? { + val dashIndex = indexOf('-') + return if (dashIndex < 0) null else substring(0, dashIndex) + } + private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean { if (callableDescriptor is FictitiousArrayConstructor) return true val name = callableDescriptor.name.asString() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt index 1c55e80c49a..a3290f8cc42 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt @@ -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.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.writeVersionRequirement import org.jetbrains.kotlin.serialization.SerializerExtension @@ -54,6 +55,7 @@ class JvmSerializerExtension @JvmOverloads constructor( private val languageVersionSettings = state.languageVersionSettings private val isParamAssertionsDisabled = state.isParamAssertionsDisabled private val unifiedNullChecks = state.unifiedNullChecks + private val functionsWithInlineClassReturnTypesMangled = state.functionsWithInlineClassReturnTypesMangled override val metadataVersion = state.metadataVersion private val jvmDefaultMode = state.jvmDefaultMode @@ -75,17 +77,17 @@ class JvmSerializerExtension @JvmOverloads constructor( } override fun serializeClass( - descriptor: ClassDescriptor, - proto: ProtoBuf.Class.Builder, - versionRequirementTable: MutableVersionRequirementTable, - childSerializer: DescriptorSerializer + descriptor: ClassDescriptor, + proto: ProtoBuf.Class.Builder, + versionRequirementTable: MutableVersionRequirementTable, + childSerializer: DescriptorSerializer ) { if (moduleName != JvmProtoBufUtil.DEFAULT_MODULE_NAME) { proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName)) } //TODO: support local delegated properties in new defaults scheme val containerAsmType = - if (DescriptorUtils.isInterface(descriptor)) typeMapper.mapDefaultImpls(descriptor) else typeMapper.mapClass(descriptor) + if (isInterface(descriptor)) typeMapper.mapDefaultImpls(descriptor) else typeMapper.mapClass(descriptor) writeLocalProperties(proto, containerAsmType, JvmProtoBuf.classLocalVariable) writeVersionRequirementForJvmDefaultIfNeeded(descriptor, proto, versionRequirementTable) @@ -198,6 +200,10 @@ class JvmSerializerExtension @JvmOverloads constructor( if (descriptor.needsInlineParameterNullCheckRequirement()) { versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement) } + + if (requiresFunctionNameManglingForReturnType(descriptor)) { + versionRequirementTable?.writeFunctionNameManglingForReturnTypeRequirement(proto::addVersionRequirement) + } } private fun MutableVersionRequirementTable.writeInlineParameterNullCheckRequirement(add: (Int) -> Unit) { @@ -208,6 +214,12 @@ class JvmSerializerExtension @JvmOverloads constructor( } } + private fun MutableVersionRequirementTable.writeFunctionNameManglingForReturnTypeRequirement(add: (Int) -> Unit) { + if (functionsWithInlineClassReturnTypesMangled) { + add(writeVersionRequirement(1, 4, 0, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, this)) + } + } + private fun FunctionDescriptor.needsInlineParameterNullCheckRequirement(): Boolean = isInline && !isSuspend && !isParamAssertionsDisabled && !Visibilities.isPrivate(visibility) && @@ -253,6 +265,10 @@ class JvmSerializerExtension @JvmOverloads constructor( if (getter?.needsInlineParameterNullCheckRequirement() == true || setter?.needsInlineParameterNullCheckRequirement() == true) { versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement) } + + if (requiresFunctionNameManglingForReturnType(descriptor)) { + versionRequirementTable?.writeFunctionNameManglingForReturnTypeRequirement(proto::addVersionRequirement) + } } private fun PropertyDescriptor.isJvmFieldPropertyInInterfaceCompanion(): Boolean { @@ -262,7 +278,7 @@ class JvmSerializerExtension @JvmOverloads constructor( if (!DescriptorUtils.isCompanionObject(container)) return false val grandParent = (container as ClassDescriptor).containingDeclaration - return DescriptorUtils.isInterface(grandParent) || DescriptorUtils.isAnnotationClass(grandParent) + return isInterface(grandParent) || DescriptorUtils.isAnnotationClass(grandParent) } override fun serializeErrorType(type: KotlinType, builder: ProtoBuf.Type.Builder) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index e13118c2e24..9bbb1bacfe5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -251,6 +251,7 @@ class GenerationState private constructor( val isInlineDisabled: Boolean = configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE) val useTypeTableInSerializer: Boolean = configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE) val unifiedNullChecks: Boolean = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 + val functionsWithInlineClassReturnTypesMangled: Boolean = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 val rootContext: CodegenContext<*> = RootContext(this) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/inlineClassManglingUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/inlineClassManglingUtils.kt index 09e0b1d0f7d..de2f1272cf8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/inlineClassManglingUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/inlineClassManglingUtils.kt @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspend import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe -import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.types.KotlinType @@ -31,11 +30,9 @@ fun getManglingSuffixBasedOnKotlinSignature(descriptor: CallableMemberDescriptor // If a class member function returns inline class value, mangle its name. // NB here function can be a suspend function JVM view with return type replaced with 'Any', // should unwrap it and take original return type instead. - if (descriptor.containingDeclaration is ClassDescriptor) { - val returnType = descriptor.unwrapInitialDescriptorForSuspendFunction().returnType!! - if (requiresFunctionNameManglingForReturnType(returnType)) { - return "-" + md5base64(":" + getSignatureElementForMangling(returnType)) - } + val unwrappedDescriptor = descriptor.unwrapInitialDescriptorForSuspendFunction() + if (requiresFunctionNameManglingForReturnType(unwrappedDescriptor)) { + return "-" + md5base64(":" + getSignatureElementForMangling(unwrappedDescriptor.returnType!!)) } return null } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt index 3854b6335ee..4ee2beb2eed 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt @@ -151,7 +151,7 @@ class JvmNameAnnotationChecker : DeclarationChecker { diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry)) } else if (descriptor.containingDeclaration.isInlineClassThatRequiresMangling() || requiresFunctionNameManglingForParameterTypes(descriptor.valueParameters.map { it.type }) || - descriptor.containingDeclaration is ClassDescriptor && requiresFunctionNameManglingForReturnType(descriptor.returnType) + requiresFunctionNameManglingForReturnType(descriptor) ) { diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry)) } diff --git a/compiler/testData/versionRequirement/inlineClassReturnTypeMangled.kt b/compiler/testData/versionRequirement/inlineClassReturnTypeMangled.kt new file mode 100644 index 00000000000..4a61bffc516 --- /dev/null +++ b/compiler/testData/versionRequirement/inlineClassReturnTypeMangled.kt @@ -0,0 +1,8 @@ +package test + +inline class IC(val x: Int) + +class C { + fun returnsInlineClassType(): IC = IC(42) + val propertyOfInlineClassType: IC get() = IC(42) +} diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt index 1bdac9ccf45..f4d261a09a6 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/AbstractVersionRequirementTest.kt @@ -33,33 +33,49 @@ abstract class AbstractVersionRequirementTest : TestCaseWithTmpdir() { fqNamesWithRequirements: List, fqNamesWithoutRequirement: List = emptyList() ) { - compileFiles(listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), tmpdir, customLanguageVersion, analysisFlags) + compileFiles( + listOf(File("compiler/testData/versionRequirement/${getTestName(true)}.kt")), + tmpdir, customLanguageVersion, analysisFlags + ) val module = loadModule(tmpdir) for (fqName in fqNamesWithRequirements) { val descriptor = module.findUnambiguousDescriptorByFqName(fqName) - val requirement = extractRequirement(descriptor) ?: throw AssertionError("No VersionRequirement for $descriptor") + val requirements = extractRequirement(descriptor) + if (requirements.isEmpty()) throw AssertionError("No VersionRequirement for $descriptor") - assertEquals("Incorrect version for $fqName", expectedVersionRequirement, requirement.version) - assertEquals("Incorrect level for $fqName", expectedLevel, requirement.level) - assertEquals("Incorrect message for $fqName", expectedMessage, requirement.message) - assertEquals("Incorrect versionKind for $fqName", expectedVersionKind, requirement.kind) - assertEquals("Incorrect errorCode for $fqName", expectedErrorCode, requirement.errorCode) + requirements.firstOrNull { + expectedVersionRequirement == it.version && + expectedLevel == it.level && + expectedMessage == it.message && + expectedVersionKind == it.kind && + expectedErrorCode == it.errorCode + } + ?: throw AssertionError( + "Version requirement not found:\n" + + "expectedVersionRequirement=" + expectedVersionRequirement + + "; expectedLevel=" + expectedLevel + + "; expectedMessage=" + expectedMessage + + "; expectedVersionKind=" + expectedVersionKind + + "; expectedErrorCode=" + expectedErrorCode + + "\nActual requirements:\n" + + requirements.joinToString(separator = "\n") { it.toString() } + ) } for (fqName in fqNamesWithoutRequirement) { val descriptor = module.findUnambiguousDescriptorByFqName(fqName) - val requirenment = extractRequirement(descriptor) - assertNull("Expecting absence of any requirements for $fqName, but `$requirenment`", requirenment) + val requirement = extractRequirement(descriptor) + assertTrue("Expecting absence of any requirements for $fqName, but `$requirement`", requirement.isEmpty()) } } - private fun extractRequirement(descriptor: DeclarationDescriptor): VersionRequirement? { + private fun extractRequirement(descriptor: DeclarationDescriptor): List { return when (descriptor) { - is DeserializedMemberDescriptor -> descriptor.versionRequirements.singleOrNull() - is DeserializedClassDescriptor -> descriptor.versionRequirements.singleOrNull() + is DeserializedMemberDescriptor -> descriptor.versionRequirements + is DeserializedClassDescriptor -> descriptor.versionRequirements else -> throw AssertionError("Unknown descriptor: $descriptor") } } diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt index c421ab38907..65bea2d6978 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt @@ -128,6 +128,17 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() { ) } + fun testInlineClassReturnTypeMangled() { + doTest( + VersionRequirement.Version(1, 4, 0), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, + fqNamesWithRequirements = listOf( + "test.C.returnsInlineClassType", + "test.C.propertyOfInlineClassType" + ), + customLanguageVersion = LanguageVersion.KOTLIN_1_4 + ) + } + fun testSuspendFun_1_2() { doTest( VersionRequirement.Version(1, 1), DeprecationLevel.ERROR, null, LANGUAGE_VERSION, null, diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/inlineClassManglingRules.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/inlineClassManglingRules.kt index 3179b231efb..1088d8ac532 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/inlineClassManglingRules.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/resolve/jvm/inlineClassManglingRules.kt @@ -29,8 +29,11 @@ fun requiresFunctionNameManglingForParameterTypes(valueParameterTypes: List