From 0182c09318d7e430778a1355c6e647b08bfaffa8 Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Tue, 29 Sep 2020 14:00:38 +0300 Subject: [PATCH] [JS IR] fix name clashes for imported external declarations --- .../kotlin/ir/backend/js/utils/IrNamerImpl.kt | 52 +++++++++++++++++++ .../kotlin/ir/backend/js/utils/NameTables.kt | 2 +- .../backend/js/utils/StableNamesCollector.kt | 3 +- .../kotlin/ir/backend/js/utils/misc.kt | 7 +++ .../box/jsModule/externalClassNameClash.js | 29 +++++++++++ .../box/jsModule/externalClassNameClash.kt | 40 ++++++++++++++ 6 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 js/js.translator/testData/box/jsModule/externalClassNameClash.js create mode 100644 js/js.translator/testData/box/jsModule/externalClassNameClash.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrNamerImpl.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrNamerImpl.kt index 2674710bf3b..d705a2d6066 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrNamerImpl.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrNamerImpl.kt @@ -9,6 +9,10 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.backend.common.ir.isTopLevel +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrLoop +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.js.backend.ast.JsName class IrNamerImpl( @@ -28,4 +32,52 @@ class IrNamerImpl( require(!field.isStatic) return newNameTables.getNameForMemberField(field).toJsName() } + + override fun getNameForField(field: IrField): JsName { + return if (field.isStatic || field.parent is IrScript) { + getNameForStaticDeclaration(field) + } else { + getNameForMemberField(field) + } + } + + override fun getNameForValueDeclaration(declaration: IrValueDeclaration): JsName = + getNameForStaticDeclaration(declaration) + + override fun getNameForClass(klass: IrClass): JsName = + getNameForStaticDeclaration(klass) + + override fun getNameForStaticFunction(function: IrSimpleFunction): JsName = + getNameForStaticDeclaration(function) + + override fun getNameForProperty(property: IrProperty): JsName = + if (property.isTopLevel) getNameForStaticDeclaration(property) else property.getJsNameOrKotlinName().asString().toJsName() + + override fun getRefForExternalClass(klass: IrClass): JsNameRef { + val parent = klass.parent + if (klass.isCompanion) + return getRefForExternalClass(parent as IrClass) + + val currentClassName = if (klass.isTopLevel) getNameForStaticDeclaration(klass).ident else klass.getJsNameOrKotlinName().identifier + return when (parent) { + is IrClass -> + JsNameRef(currentClassName, getRefForExternalClass(parent)) + + is IrPackageFragment -> + JsNameRef(currentClassName) + + else -> + error("Unsupported external class parent $parent") + } + } + + private val associatedObjectKeyMap = mutableMapOf() + + override fun getAssociatedObjectKey(irClass: IrClass): Int? { + if (irClass.isAssociatedObjectAnnotatedAnnotation) { + + return associatedObjectKeyMap.getOrPut(irClass) { associatedObjectKeyMap.size } + } + return null + } } 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 b89f40aa49b..60725596408 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 @@ -286,7 +286,7 @@ class NameTables( return // TODO: Handle JsQualifier - declaration.isEffectivelyExternal() && (declaration.getJsModule() == null || declaration.isJsNonModule()) -> { + declaration.isEffectivelyExternal() && !declaration.isImportedFromModuleOnly() -> { if (declaration.file.getJsModule() != null) { globalNames.declareFreshName(declaration, declaration.name.asString()) } else { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/StableNamesCollector.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/StableNamesCollector.kt index 5699b3bc3c7..f263a3a69a5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/StableNamesCollector.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/StableNamesCollector.kt @@ -73,8 +73,7 @@ class StableNamesCollector : IrElementVisitorVoid { return null } - val importedFromModuleOnly = - declaration.getJsModule() != null && !declaration.isJsNonModule() + val importedFromModuleOnly = declaration.isImportedFromModuleOnly() val jsName = declaration.getJsName() val jsQualifier = declaration.getJsQualifier() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt index c1daf564382..85cdf894e5d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.ir.backend.js.utils import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny +import org.jetbrains.kotlin.backend.common.ir.isTopLevel import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext @@ -18,6 +19,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullableAny +import org.jetbrains.kotlin.ir.types.isUnit +import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration import org.jetbrains.kotlin.name.Name @@ -111,4 +114,8 @@ fun IrBody.prependFunctionCall( ) } } +} + +fun IrDeclaration.isImportedFromModuleOnly(): Boolean { + return isTopLevel && isEffectivelyExternal() && (getJsModule() != null && !isJsNonModule() || (parent as? IrAnnotationContainer)?.getJsModule() != null) } \ No newline at end of file diff --git a/js/js.translator/testData/box/jsModule/externalClassNameClash.js b/js/js.translator/testData/box/jsModule/externalClassNameClash.js new file mode 100644 index 00000000000..ead4e0502a3 --- /dev/null +++ b/js/js.translator/testData/box/jsModule/externalClassNameClash.js @@ -0,0 +1,29 @@ +define("a", [], function() { + + function A() {} + + A.prototype.foo = function () { + return "O"; + }; + + return { + A: A, + bar: function() { return 1; }, + prop: 10 + }; +}); + +define("b", [], function() { + + function A() {} + + A.prototype.foo = function () { + return "K"; + }; + + return { + A: A, + bar: function() { return 2; }, + prop: 20 + }; +}); \ No newline at end of file diff --git a/js/js.translator/testData/box/jsModule/externalClassNameClash.kt b/js/js.translator/testData/box/jsModule/externalClassNameClash.kt new file mode 100644 index 00000000000..82bd9e6c440 --- /dev/null +++ b/js/js.translator/testData/box/jsModule/externalClassNameClash.kt @@ -0,0 +1,40 @@ +// EXPECTED_REACHABLE_NODES: 1284 +// FILE: a.kt +// MODULE_KIND: AMD +@file:JsModule("a") +package a + +external class A { + fun foo(): String +} + +external fun bar(): Int + +external val prop: Int + +// FILE: b.kt +// MODULE_KIND: AMD +@file:JsModule("b") +package b + +external class A { + fun foo(): String +} + +external fun bar(): Int + +external var prop: Int + +// FILE: main.kt + +import a.A as O +import b.A as K + +fun box(): String { + if (a.bar() != 1) return "fail 1" + if (a.prop != 10) return "fail 2" + if (b.bar() != 2) return "fail 3" + if (b.prop != 20) return "fail 4" + + return O().foo() + K().foo() +} \ No newline at end of file