diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 8f6f013105c..ab280c942e7 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -77,6 +77,7 @@ class JsIrBackendContext( val globalInternationService = IrInterningService() val localClassNames = WeakHashMap() + val classToItsId = WeakHashMap() val minimizedNameGenerator: MinimizedNameGenerator = MinimizedNameGenerator() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 31b8c8aa15c..0fcf41f97ff 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -163,6 +163,12 @@ val createScriptFunctionsPhase = makeJsModulePhase( description = "Create functions for initialize and evaluate script" ).toModuleLowering() +private val collectClassIdentifiersLowering = makeJsModulePhase( + ::JsCollectClassIdentifiersLowering, + name = "CollectClassIdentifiersLowering", + description = "Save classId before all the lowerings", +).toModuleLowering() + private val inventNamesForLocalClassesPhase = makeJsModulePhase( ::JsInventNamesForLocalClasses, name = "InventNamesForLocalClasses", @@ -862,6 +868,7 @@ val loweringList = listOf( validateIrBeforeLowering, preventExportOfSyntheticDeclarationsLowering, inventNamesForLocalClassesPhase, + collectClassIdentifiersLowering, annotationInstantiationLowering, expectDeclarationsRemovingPhase, stripTypeAliasDeclarationsPhase, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCollectClassIdentifiersLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCollectClassIdentifiersLowering.kt new file mode 100644 index 00000000000..84702fd5af3 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsCollectClassIdentifiersLowering.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.DeclarationTransformer +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.util.classId + +class JsCollectClassIdentifiersLowering(private val context: JsIrBackendContext) : DeclarationTransformer { + override fun transformFlat(declaration: IrDeclaration): List? { + if (declaration is IrClass) { + declaration.classId?.let { context.classToItsId[declaration] = it.toString() } + } + return null + } +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrTypeUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrTypeUtils.kt index 14681256ffe..e236cd2df7b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrTypeUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrTypeUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName @@ -13,6 +14,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.js.backend.ast.JsExpression @@ -22,33 +24,38 @@ import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jetbrains.kotlin.utils.addToStdlib.butIf -fun IrType.asString(): String = when (this) { +fun IrType.asString(context: JsIrBackendContext): String = when (this) { // TODO: should each IrErrorType have own string representation? is IrErrorType -> "\$ErrorType\$" // TODO: should we prohibit user classes called dynamic? is IrDynamicType -> "dynamic" is IrSimpleType -> - classifier.asString() + + classifier.asString(context) + when (nullability) { SimpleTypeNullability.MARKED_NULLABLE -> "?" SimpleTypeNullability.NOT_SPECIFIED -> "" SimpleTypeNullability.DEFINITELY_NOT_NULL -> if (classifier is IrTypeParameterSymbol) " & Any" else "" } + (arguments.ifNotEmpty { - joinToString(separator = ",", prefix = "<", postfix = ">") { it.asString() } + joinToString(separator = ",", prefix = "<", postfix = ">") { it.asString(context) } } ?: "") else -> error("Unexpected kind of IrType: " + javaClass.typeName) } -private fun IrTypeArgument.asString(): String = when (this) { +private fun IrTypeArgument.asString(context: JsIrBackendContext): String = when (this) { is IrStarProjection -> "*" - is IrTypeProjection -> variance.label + (if (variance != Variance.INVARIANT) " " else "") + type.asString() + is IrTypeProjection -> variance.label + (if (variance != Variance.INVARIANT) " " else "") + type.asString(context) } -private fun IrClassifierSymbol.asString() = when (this) { - is IrTypeParameterSymbol -> this.owner.name.asString() - is IrClassSymbol -> this.owner.fqNameWhenAvailable!!.asString() - is IrScriptSymbol -> unexpectedSymbolKind() +private fun IrClassifierSymbol.asString(context: JsIrBackendContext): String { + return when (this) { + is IrTypeParameterSymbol -> this.owner.name.asString() + is IrScriptSymbol -> unexpectedSymbolKind() + is IrClassSymbol -> + context.classToItsId[owner] + ?: context.localClassNames[owner] + ?: this.owner.fqNameWhenAvailable!!.asString() + } } tailrec fun erase(type: IrType): IrClass? = when (val classifier = type.classifierOrFail) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt index bf5801ec213..f0199346ddf 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt @@ -116,11 +116,11 @@ fun Int.toJsIdentifier(): String { } } -private fun List.joinTypes(): String { +private fun List.joinTypes(context: JsIrBackendContext): String { if (isEmpty()) { return "" } - return joinToString("$", "$") { superType -> superType.asString() } + return joinToString("$", "$") { superType -> superType.asString(context) } } fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): String { @@ -133,25 +133,25 @@ fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendCo declaration.typeParameters.ifNotEmpty { nameBuilder.append("_\$t") forEach { typeParam -> - nameBuilder.append("_").append(typeParam.name.asString()).append(typeParam.superTypes.joinTypes()) + nameBuilder.append("_").append(typeParam.name.asString()).append(typeParam.superTypes.joinTypes(context)) } } declaration.extensionReceiverParameter?.let { - val superTypes = it.type.superTypes().joinTypes() - nameBuilder.append("_r$${it.type.asString()}$superTypes") + val superTypes = it.type.superTypes().joinTypes(context) + nameBuilder.append("_r$${it.type.asString(context)}$superTypes") } declaration.valueParameters.ifNotEmpty { joinTo(nameBuilder, "") { val defaultValueSign = if (it.origin == JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER) "?" else "" - val superTypes = it.type.superTypes().joinTypes() - "_${it.type.asString()}$superTypes$defaultValueSign" + val superTypes = it.type.superTypes().joinTypes(context) + "_${it.type.asString(context)}$superTypes$defaultValueSign" } } declaration.returnType.let { // Return type is only used in signature for inline class and Unit types because // they are binary incompatible with supertypes. if (context.inlineClassesUtils.isTypeInlined(it) || it.isUnit()) { - nameBuilder.append("_ret$${it.asString()}") + nameBuilder.append("_ret$${it.asString(context)}") } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java index 927f8fa9131..e0260b6685d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java @@ -8270,6 +8270,18 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest { runTest("js/js.translator/testData/box/nameClashes/overloadExtension.kt"); } + @Test + @TestMetadata("overloadMethodsWithSameParameterPrivateTypeName.kt") + public void testOverloadMethodsWithSameParameterPrivateTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt"); + } + + @Test + @TestMetadata("overloadMethodsWithSameParameterTypeName.kt") + public void testOverloadMethodsWithSameParameterTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt"); + } + @Test @TestMetadata("propertyAndNativeMethod.kt") public void testPropertyAndNativeMethod() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java index d3d943c6e8d..0b47fa2a432 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java @@ -8376,6 +8376,18 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { runTest("js/js.translator/testData/box/nameClashes/overloadExtension.kt"); } + @Test + @TestMetadata("overloadMethodsWithSameParameterPrivateTypeName.kt") + public void testOverloadMethodsWithSameParameterPrivateTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt"); + } + + @Test + @TestMetadata("overloadMethodsWithSameParameterTypeName.kt") + public void testOverloadMethodsWithSameParameterTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt"); + } + @Test @TestMetadata("propertyAndNativeMethod.kt") public void testPropertyAndNativeMethod() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 69504024299..2a5aea4f9d6 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -8270,6 +8270,18 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/nameClashes/overloadExtension.kt"); } + @Test + @TestMetadata("overloadMethodsWithSameParameterPrivateTypeName.kt") + public void testOverloadMethodsWithSameParameterPrivateTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt"); + } + + @Test + @TestMetadata("overloadMethodsWithSameParameterTypeName.kt") + public void testOverloadMethodsWithSameParameterTypeName() throws Exception { + runTest("js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt"); + } + @Test @TestMetadata("propertyAndNativeMethod.kt") public void testPropertyAndNativeMethod() throws Exception { diff --git a/js/js.translator/testData/box/inline/extensionWithManyArguments.kt b/js/js.translator/testData/box/inline/extensionWithManyArguments.kt index 412188e41e2..7e8ae900c21 100644 --- a/js/js.translator/testData/box/inline/extensionWithManyArguments.kt +++ b/js/js.translator/testData/box/inline/extensionWithManyArguments.kt @@ -1,7 +1,7 @@ // EXPECTED_REACHABLE_NODES: 1285 package foo -// CHECK_CONTAINS_NO_CALLS: myMultiply except=A;imul;new_foo_A_rthawl_k$ +// CHECK_CONTAINS_NO_CALLS: myMultiply except=A;imul;new_foo_A_eb0rqk_k$ internal class A(val a: Int) diff --git a/js/js.translator/testData/box/inline/privateProperty.kt b/js/js.translator/testData/box/inline/privateProperty.kt index 151d5e7b1fa..36351633afc 100644 --- a/js/js.translator/testData/box/inline/privateProperty.kt +++ b/js/js.translator/testData/box/inline/privateProperty.kt @@ -104,8 +104,8 @@ private class A { // CHECK_NOT_CALLED_IN_SCOPE: function=get_p12_s8ev3n$ scope=box TARGET_BACKENDS=JS // CHECK_FUNCTION_EXISTS: set_p12_dqglrj$ TARGET_BACKENDS=JS // CHECK_NOT_CALLED_IN_SCOPE: function=set_p12_dqglrj$ scope=box TARGET_BACKENDS=JS - // CHECK_NOT_CALLED_IN_SCOPE: function=get_p12_jvqn3p_k$ scope=box IGNORED_BACKENDS=JS - // CHECK_NOT_CALLED_IN_SCOPE: function=set_p12_na24b5_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_NOT_CALLED_IN_SCOPE: function=get_p12_qp3nj6_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_NOT_CALLED_IN_SCOPE: function=set_p12_5gautq_k$ scope=box IGNORED_BACKENDS=JS inline var Int.p12: Int get() = this * 100 + a + 120000 set(v) { @@ -115,9 +115,9 @@ private class A { // CHECK_FUNCTION_EXISTS: get_p13_s8ev3n$ TARGET_BACKENDS=JS // CHECK_NOT_CALLED_IN_SCOPE: function=get_p13_s8ev3n$ scope=box TARGET_BACKENDS=JS // CHECK_CALLED_IN_SCOPE: function=set_p13_dqglrj$ scope=box TARGET_BACKENDS=JS - // CHECK_FUNCTION_EXISTS: get_p13_v9rv0h_k$ IGNORED_BACKENDS=JS - // CHECK_NOT_CALLED_IN_SCOPE: function=get_p13_v9rv0h_k$ scope=box IGNORED_BACKENDS=JS - // CHECK_CALLED_IN_SCOPE: function=set_p13_7j3jda_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_FUNCTION_EXISTS: get_p13_58c7pb_k$ IGNORED_BACKENDS=JS + // CHECK_NOT_CALLED_IN_SCOPE: function=get_p13_58c7pb_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_CALLED_IN_SCOPE: function=set_p13_daivm5_k$ scope=box IGNORED_BACKENDS=JS var Int.p13: Int inline get() = this * 100 + a + 130000 set(v) { @@ -127,9 +127,9 @@ private class A { // CHECK_CALLED_IN_SCOPE: function=get_p14_s8ev3n$ scope=box TARGET_BACKENDS=JS // CHECK_FUNCTION_EXISTS: set_p14_dqglrj$ TARGET_BACKENDS=JS // CHECK_NOT_CALLED_IN_SCOPE: function=set_p14_dqglrj$ scope=box TARGET_BACKENDS=JS - // CHECK_CALLED_IN_SCOPE: function=get_p14_7twbq6_k$ scope=box IGNORED_BACKENDS=JS - // CHECK_FUNCTION_EXISTS: set_p14_fdbk5p_k$ IGNORED_BACKENDS=JS - // CHECK_NOT_CALLED_IN_SCOPE: function=set_p14_fdbk5p_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_CALLED_IN_SCOPE: function=get_p14_xvbz1c_k$ scope=box IGNORED_BACKENDS=JS + // CHECK_FUNCTION_EXISTS: set_p14_l4qwek_k$ IGNORED_BACKENDS=JS + // CHECK_NOT_CALLED_IN_SCOPE: function=set_p14_l4qwek_k$ scope=box IGNORED_BACKENDS=JS var Int.p14: Int get() = this * 100 + a + 140000 inline set(v) { diff --git a/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt b/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt new file mode 100644 index 00000000000..29a12c25752 --- /dev/null +++ b/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterPrivateTypeName.kt @@ -0,0 +1,47 @@ +// EXPECTED_REACHABLE_NODES: 1281 +package foo + +private class Foo{ + data class Id(val uuid: Int) +} +private class Bar{ + data class Id(val uuid: Int) +} + +private class E1 { + enum class Id { A } +} + +private class E2 { + enum class Id { A } +} + +private class O1 { + object Id +} + +private class O2 { + object Id +} + +private class Service{ + operator fun get(id: Foo.Id) = "Foo getter" + operator fun get(id: Bar.Id) = "Bar getter" + + operator fun get(id: E1.Id) = "E1 getter" + operator fun get(id: E2.Id) = "E2 getter" + + operator fun get(id: O1.Id) = "O1 getter" + operator fun get(id: O2.Id) = "O2 getter" +} + +fun box(): String { + var service = Service() + if (service[Bar.Id(12)] != "Bar getter") return "Fail with Bar overload" + if (service[Foo.Id(6)] != "Foo getter") return "Fail with Foo overload" + if (service[E1.Id.A] != "E1 getter") return "Fail with E1 overload" + if (service[E2.Id.A] != "E2 getter") return "Fail with E2 overload" + if (service[O1.Id] != "O1 getter") return "Fail with O1 overload" + if (service[O2.Id] != "O2 getter") return "Fail with O2 overload" + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt b/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt new file mode 100644 index 00000000000..74a81951bbc --- /dev/null +++ b/js/js.translator/testData/box/nameClashes/overloadMethodsWithSameParameterTypeName.kt @@ -0,0 +1,47 @@ +// EXPECTED_REACHABLE_NODES: 1281 +package foo + +class Foo{ + data class Id(val uuid: Int) +} +class Bar{ + data class Id(val uuid: Int) +} + +class E1 { + enum class Id { A } +} + +class E2 { + enum class Id { A } +} + +class O1 { + object Id +} + +class O2 { + object Id +} + +class Service{ + operator fun get(id: Foo.Id) = "Foo getter" + operator fun get(id: Bar.Id) = "Bar getter" + + operator fun get(id: E1.Id) = "E1 getter" + operator fun get(id: E2.Id) = "E2 getter" + + operator fun get(id: O1.Id) = "O1 getter" + operator fun get(id: O2.Id) = "O2 getter" +} + +fun box(): String { + var service = Service() + if (service[Bar.Id(12)] != "Bar getter") return "Fail with /**/Bar overload" + if (service[Foo.Id(6)] != "Foo getter") return "Fail with Foo overload" + if (service[E1.Id.A] != "E1 getter") return "Fail with E1 overload" + if (service[E2.Id.A] != "E2 getter") return "Fail with E2 overload" + if (service[O1.Id] != "O1 getter") return "Fail with O1 overload" + if (service[O2.Id] != "O2 getter") return "Fail with O2 overload" + return "OK" +} \ No newline at end of file