JVM IR: add module name for internal functions before "$default"

The change is a bit complicated because the name mapping logic is
refactored so that we would compute the needed suffix first (either
module name, or multifile part class name), and then shove it into the
mangled name between the original function name and "$default", if the
function in question is the default arguments adapter.

The main motivation for this change was to fix KT-41809, but as a side
effect, private functions with default arguments in multifile parts now
also contain the file name, just like normal private functions.

 #KT-41809 Fixed
This commit is contained in:
Alexander Udalov
2020-09-11 17:02:25 +02:00
parent 93f38e1c61
commit f0282bcfdf
8 changed files with 129 additions and 14 deletions
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.codegen.replaceValueParametersIn
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.state.extractTypeMappingModeFromAnnotation import org.jetbrains.kotlin.codegen.state.extractTypeMappingModeFromAnnotation
import org.jetbrains.kotlin.codegen.state.isMethodWithDeclarationSiteWildcardsFqName import org.jetbrains.kotlin.codegen.state.isMethodWithDeclarationSiteWildcardsFqName
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -45,6 +44,7 @@ import org.jetbrains.kotlin.load.kotlin.signatures
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -108,25 +108,38 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
private fun mangleMemberNameIfRequired(name: String, function: IrSimpleFunction): String { private fun mangleMemberNameIfRequired(name: String, function: IrSimpleFunction): String {
val newName = JvmCodegenUtil.sanitizeNameIfNeeded(name, context.state.languageVersionSettings) val newName = JvmCodegenUtil.sanitizeNameIfNeeded(name, context.state.languageVersionSettings)
if (function.isTopLevel) { val suffix = when {
if (DescriptorVisibilities.isPrivate(function.suspendFunctionOriginal().visibility) && function.isTopLevel ->
newName != "<clinit>" && (function.parent as? IrClass)?.attributeOwnerId in context.multifileFacadeForPart if (function.isInvisibleInMultifilePart()) function.parentAsClass.name.asString() else null
) { function.shouldMangleAsInternal() ->
return "$newName$${function.parentAsClass.name.asString()}" NameUtils.sanitizeAsJavaIdentifier(getModuleName(function))
} else -> null
return newName } ?: return newName
if (function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
assert(newName.endsWith(JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX)) { "Default adapter should end with \$default: ${function.render()}" }
return newName.substringBeforeLast(JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX) + "$" + suffix + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX
} }
return if (function.shouldMangleAsInternal()) return "$newName$$suffix"
KotlinTypeMapper.InternalNameMapper.mangleInternalName(newName, getModuleName(function))
else
newName
} }
private fun IrSimpleFunction.isInvisibleInMultifilePart(): Boolean =
name.asString() != "<clinit>" &&
(parent as? IrClass)?.attributeOwnerId in context.multifileFacadeForPart &&
(DescriptorVisibilities.isPrivate(suspendFunctionOriginal().visibility) ||
originalForDefaultAdapter?.isInvisibleInMultifilePart() == true)
private fun IrSimpleFunction.shouldMangleAsInternal(): Boolean = private fun IrSimpleFunction.shouldMangleAsInternal(): Boolean =
origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR && (origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR &&
visibility == DescriptorVisibilities.INTERNAL && visibility == DescriptorVisibilities.INTERNAL &&
!isPublishedApi() !isPublishedApi())
|| originalForDefaultAdapter?.shouldMangleAsInternal() == true
private val IrSimpleFunction.originalForDefaultAdapter: IrSimpleFunction?
get() = if (origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
((body?.statements?.lastOrNull() as? IrReturn)?.value as? IrCall)?.symbol?.owner
} else null
private fun getModuleName(function: IrSimpleFunction): String = private fun getModuleName(function: IrSimpleFunction): String =
(if (function is IrLazyFunction) (if (function is IrLazyFunction)
@@ -0,0 +1,12 @@
// WITH_RUNTIME
package test
class A internal constructor(a: Int = 0) {
internal fun internalFunction(b: String = "") {}
@JvmName("internalJvmNameFunction")
internal fun f(c: String = "") {}
public fun publicFunction(d: String = "") {}
}
@@ -0,0 +1,13 @@
@kotlin.Metadata
public final class test/A {
// source: 'internalNameMangling.kt'
public method <init>(): void
public method <init>(p0: int): void
public synthetic method <init>(p0: int, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
public synthetic static method internalFunction$test_module$default(p0: test.A, p1: java.lang.String, p2: int, p3: java.lang.Object): void
public final method internalFunction$test_module(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
public synthetic static method internalJvmNameFunction$default(p0: test.A, p1: java.lang.String, p2: int, p3: java.lang.Object): void
public final @kotlin.jvm.JvmName method internalJvmNameFunction(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
public synthetic static method publicFunction$default(p0: test.A, p1: java.lang.String, p2: int, p3: java.lang.Object): void
public final method publicFunction(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
// The remaining differences of JVM and JVM_IR here are reported at KT-36970, KT-41841.
@file:JvmMultifileClass
@file:JvmName("A")
private fun foo(x: String = "") {}
@@ -0,0 +1,11 @@
@kotlin.Metadata
public final class A {
// source: 'privateFunctionInMultifilePart.kt'
}
@kotlin.Metadata
synthetic final class A__PrivateFunctionInMultifilePartKt {
// source: 'privateFunctionInMultifilePart.kt'
synthetic static method foo$A__PrivateFunctionInMultifilePartKt$default(p0: java.lang.String, p1: int, p2: java.lang.Object): void
private final static method foo$A__PrivateFunctionInMultifilePartKt(p0: java.lang.String): void
}
@@ -0,0 +1,13 @@
@kotlin.Metadata
public final class A {
// source: 'privateFunctionInMultifilePart.kt'
final static method foo$A__PrivateFunctionInMultifilePartKt$default(@org.jetbrains.annotations.Nullable p0: java.lang.String, p1: int, p2: java.lang.Object): void
}
@kotlin.Metadata
@kotlin.jvm.JvmName
synthetic final class A__PrivateFunctionInMultifilePartKt {
// source: 'privateFunctionInMultifilePart.kt'
synthetic static method foo$A__PrivateFunctionInMultifilePartKt$default(p0: java.lang.String, p1: int, p2: java.lang.Object): void
private final static method foo$A__PrivateFunctionInMultifilePartKt(p0: java.lang.String): void
}
@@ -375,6 +375,29 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
} }
} }
@TestMetadata("compiler/testData/codegen/bytecodeListing/defaultArguments")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultArguments extends AbstractBytecodeListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInDefaultArguments() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("internalNameMangling.kt")
public void testInternalNameMangling() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/defaultArguments/internalNameMangling.kt");
}
@TestMetadata("privateFunctionInMultifilePart.kt")
public void testPrivateFunctionInMultifilePart() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/defaultArguments/privateFunctionInMultifilePart.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/deprecated") @TestMetadata("compiler/testData/codegen/bytecodeListing/deprecated")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -345,6 +345,29 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
} }
} }
@TestMetadata("compiler/testData/codegen/bytecodeListing/defaultArguments")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultArguments extends AbstractIrBytecodeListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInDefaultArguments() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("internalNameMangling.kt")
public void testInternalNameMangling() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/defaultArguments/internalNameMangling.kt");
}
@TestMetadata("privateFunctionInMultifilePart.kt")
public void testPrivateFunctionInMultifilePart() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/defaultArguments/privateFunctionInMultifilePart.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeListing/deprecated") @TestMetadata("compiler/testData/codegen/bytecodeListing/deprecated")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)