diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt index c801f64c059..459aa8ad6a0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MoveBodilessDeclarationsToSeparatePlace.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol -import org.jetbrains.kotlin.ir.util.isClass import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.name.FqName @@ -68,7 +67,7 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module: externalClasses.flatMap { collectExternalClasses(it, true) } return if (includeCurrentLevel) - externalClasses.filter { it.isClass } + nestedExternalClasses + externalClasses + nestedExternalClasses else nestedExternalClasses } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index a95f6c34438..89cec83f11f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -143,13 +143,18 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) : } for (externalClass in backendContext.externalNestedClasses) { + + // External companions are not "nested". Instead they use parent class name. + if (externalClass.isCompanion) + continue + val declName = rootContext.getNameForDeclaration(externalClass) val parentName = rootContext.getNameForDeclaration(externalClass.parentAsClass) importStatements.add( JsExpressionStatement( jsAssignment( declName.makeRef(), - JsNameRef(externalClass.name.identifier, parentName.makeRef()) + JsNameRef(externalClass.getJsNameOrKotlinName().identifier, parentName.makeRef()) ) ) ) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt index f9cce1adf68..4c5476683c7 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt @@ -6,11 +6,13 @@ package org.jetbrains.kotlin.ir.backend.js.utils import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer +import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.util.getAnnotation import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name object JsAnnotations { val jsModuleFqn = FqName("kotlin.js.JsModule") @@ -33,3 +35,10 @@ fun IrAnnotationContainer.getJsQualifier(): String? = fun IrAnnotationContainer.getJsName(): String? = getAnnotation(JsAnnotations.jsNameFqn)?.getSingleConstStringArgument() + + +fun IrDeclarationWithName.getJsNameOrKotlinName(): Name = + when (val jsName = getJsName()) { + null -> name + else -> Name.identifier(jsName) + } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt index 6dc374460c8..b0ebac44787 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt @@ -32,7 +32,7 @@ class SimpleNameGenerator : NameGenerator { private val loopCache = mutableMapOf() override fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName = - if (symbol.isBound) getNameForDeclaration(symbol.owner as IrDeclaration, context) else + if (symbol.isBound) getNameForDeclaration(symbol.owner as IrDeclarationWithName, context) else declareDynamic(symbol.descriptor, context) override fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName? = loop.label?.let { @@ -40,7 +40,7 @@ class SimpleNameGenerator : NameGenerator { } override fun getNameForType(type: IrType, context: JsGenerationContext) = - getNameForDeclaration(type.classifierOrFail.owner as IrDeclaration, context) + getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context) @Deprecated("Descriptors-based code is deprecated") private fun declareDynamic(descriptor: DeclarationDescriptor, context: JsGenerationContext): JsName { @@ -91,35 +91,24 @@ class SimpleNameGenerator : NameGenerator { "Kotlin" ) - private fun getNameForDeclaration(declaration: IrDeclaration, context: JsGenerationContext): JsName = + private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName = nameCache.getOrPut(declaration) { var nameDeclarator: (String) -> JsName = context.currentScope::declareName val nameBuilder = StringBuilder() - val descriptor = declaration.descriptor - if (declaration.isDynamic()) { return@getOrPut nameDeclarator(declaration.descriptor.name.asString()) } - val jsName = declaration.getJsName() - if (jsName != null) { - return@getOrPut context.currentScope.declareName(jsName) - } + val declarationName = declaration.getJsNameOrKotlinName().asString() if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) { - return@getOrPut context.staticContext.rootScope.declareName(declaration.name.identifier) + return@getOrPut nameDeclarator(declarationName) } if (declaration.isEffectivelyExternal()) { - // TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet - val descriptorName = when (descriptor) { - is ConstructorDescriptor -> descriptor.constructedClass - is PropertyAccessorDescriptor -> descriptor.correspondingProperty - else -> descriptor - }.name - - if (declaration is IrConstructor) return@getOrPut getNameForDeclaration(declaration.parentAsClass, context) + if (declaration is IrConstructor) + return@getOrPut getNameForDeclaration(declaration.parentAsClass, context) if (declaration is IrClass && declaration.parent is IrClass) { val parentName = getNameForDeclaration(declaration.parentAsClass, context) @@ -127,9 +116,14 @@ class SimpleNameGenerator : NameGenerator { // External companions are class references return@getOrPut parentName } - return@getOrPut context.currentScope.declareFreshName(parentName.ident + "$" + descriptorName.identifier) + return@getOrPut context.currentScope.declareFreshName(parentName.ident + "$" + declarationName) } - return@getOrPut context.staticContext.rootScope.declareName(descriptorName.identifier) + return@getOrPut nameDeclarator(declarationName) + } + + val jsName = declaration.getJsName() + if (jsName != null) { + return@getOrPut context.currentScope.declareName(jsName) } when (declaration) { @@ -141,7 +135,7 @@ class SimpleNameGenerator : NameGenerator { else if (declaration == context.currentFunction?.extensionReceiverParameter) { nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME) } else { - val declaredName = declaration.name.asString() + val declaredName = declarationName nameBuilder.append(declaredName) if (declaredName.startsWith("\$")) { nameBuilder.append('.') @@ -151,22 +145,22 @@ class SimpleNameGenerator : NameGenerator { } } is IrField -> { - nameBuilder.append(declaration.name.asString()) + nameBuilder.append(declarationName) if (declaration.isTopLevel) { nameDeclarator = context.staticContext.rootScope::declareFreshName } else { nameBuilder.append('.') - nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context)) + nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName } } is IrClass -> { if (declaration.isCompanion) { - nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context)) + nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) nameBuilder.append('.') } - nameBuilder.append(declaration.name.asString()) + nameBuilder.append(declarationName) (declaration.parent as? IrClass)?.let { nameBuilder.append("$") @@ -181,7 +175,7 @@ class SimpleNameGenerator : NameGenerator { } val parent = declaration.parent when (parent) { - is IrDeclaration -> nameBuilder.append(getNameForDeclaration(parent, context)) + is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context)) is IrPackageFragment -> nameBuilder.append(parent.fqName.asString()) } } @@ -204,14 +198,14 @@ class SimpleNameGenerator : NameGenerator { is IrSimpleFunction -> { if (declaration.isStaticMethodOfClass) { - nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context)) + nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context)) nameBuilder.append('.') } if (declaration.dispatchReceiverParameter == null) { nameDeclarator = context.staticContext.rootScope::declareFreshName } - nameBuilder.append(declaration.name.asString()) + nameBuilder.append(declarationName) // TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters? declaration.typeParameters.ifNotEmpty { nameBuilder.append("_\$t") diff --git a/js/js.translator/testData/box/native/nestedElements.kt b/js/js.translator/testData/box/native/nestedElements.kt index a9356024b3d..1810fa9c0d4 100644 --- a/js/js.translator/testData/box/native/nestedElements.kt +++ b/js/js.translator/testData/box/native/nestedElements.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // EXPECTED_REACHABLE_NODES: 1310 package foo