diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 475318cea4d..68ca9159616 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.js.translate.declaration.ClassModelGenerator; import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; +import org.jetbrains.kotlin.js.translate.utils.SignatureUtilsKt; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; @@ -115,6 +116,8 @@ public final class StaticContext { @NotNull private final Map fqnCache = new HashMap<>(); + private final Map tagCache = new HashMap<>(); + @NotNull private final Map importedModules = new LinkedHashMap<>(); @@ -123,9 +126,6 @@ public final class StaticContext { @NotNull private final JsScope rootPackageScope; - @NotNull - private final List importStatements = new ArrayList<>(); - @NotNull private final DeclarationExporter exporter = new DeclarationExporter(this); @@ -220,6 +220,19 @@ public final class StaticContext { return (JsNameRef) getQualifiedExpression(descriptor); } + @Nullable + private String getTag(@NotNull DeclarationDescriptor descriptor) { + String tag; + if (!tagCache.containsKey(descriptor)) { + tag = SignatureUtilsKt.generateSignature(descriptor); + tagCache.put(descriptor, tag); + } + else { + tag = tagCache.get(descriptor); + } + return tag; + } + @NotNull private JsExpression getQualifiedExpression(@NotNull DeclarationDescriptor descriptor) { JsExpression fqn = fqnCache.computeIfAbsent(descriptor, this::buildQualifiedExpression); @@ -451,7 +464,7 @@ public final class StaticContext { } @NotNull - public JsName importDeclaration(@NotNull String suggestedName, @NotNull JsExpression declaration) { + public JsName importDeclaration(@NotNull String suggestedName, @NotNull String tag, @NotNull JsExpression declaration) { // Adding prefix is a workaround for a problem with scopes. // Consider we declare name `foo` in functions's local scope, then call top-level function `foo` // from another module. It's imported into global scope under name `foo`. If we could somehow @@ -461,16 +474,25 @@ public final class StaticContext { JsName result = fragment.getScope().declareTemporaryName(suggestedName); MetadataProperties.setImported(result, true); - importStatements.add(JsAstUtils.newVar(result, declaration)); + fragment.getImports().put(tag, declaration); return result; } @NotNull private JsName localOrImportedName(@NotNull DeclarationDescriptor descriptor, @NotNull String suggestedName) { ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor); - JsName name = module != currentModule ? - importDeclaration(suggestedName, getQualifiedReference(descriptor)) : - fragment.getScope().declareTemporaryName(suggestedName); + JsName name; + String tag = getTag(descriptor); + if (module != currentModule) { + assert tag != null : "Can't import declaration without fqname: " + descriptor; + name = importDeclaration(suggestedName, tag, getQualifiedReference(descriptor)); + } + else { + name = fragment.getScope().declareTemporaryName(suggestedName); + } + if (tag != null) { + fragment.getNameBindings().add(new JsNameBinding(tag, name)); + } MetadataProperties.setDescriptor(name, descriptor); return name; } @@ -672,14 +694,13 @@ public final class StaticContext { return suggestedName.getNames().get(0); } - private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) { + private static void applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) { if (descriptor instanceof FunctionDescriptor || descriptor instanceof PackageFragmentDescriptor || descriptor instanceof ClassDescriptor - ) { + ) { MetadataProperties.setSideEffects(expression, SideEffectKind.PURE); } - return expression; } public void putClassOrConstructorClosure(@NotNull MemberDescriptor localClass, @NotNull List closure) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt index dd6488520c2..f01090b9610 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Merger.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata import org.jetbrains.kotlin.js.inline.clean.resolveTemporaryNames import org.jetbrains.kotlin.js.translate.context.Namer +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName) { // Maps unique signature (see generateSignature) to names @@ -28,12 +29,20 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam private val declarationBlock = JsGlobalBlock() private val initializerBlock = JsGlobalBlock() private val exportBlock = JsGlobalBlock() + private val declaredImports = mutableSetOf() // Add declaration and initialization statements from program fragment to resulting single program fun addFragment(fragment: JsProgramFragment) { val nameMap = buildNameMap(fragment) nameMap.rename(fragment) + for ((key, importExpr) in fragment.imports) { + if (declaredImports.add(key)) { + val name = nameTable[key]!! + importBlock.statements += JsAstUtils.newVar(nameMap.rename(name), nameMap.rename(importExpr)) + } + } + declarationBlock.statements += fragment.declarationBlock initializerBlock.statements += fragment.initializerBlock exportBlock.statements += fragment.exportBlock diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java index cba9d542e4a..e3f44cb22f3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java @@ -262,7 +262,8 @@ public final class Translation { ) { JsProgram program = new JsProgram(); JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function"); - Merger merger = new Merger(rootFunction); + JsName internalModuleName = program.getScope().declareName("_"); + Merger merger = new Merger(rootFunction, internalModuleName); List fragments = new ArrayList(); for (KtFile file : files) { @@ -279,8 +280,6 @@ public final class Translation { List statements = rootBlock.getStatements(); - program.getScope().declareName("_"); - //staticContext.postProcess(); statements.add(0, program.getStringLiteral("use strict").makeStmt()); if (!isBuiltinModule(fragments)) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt index 0bf23235113..41910d9149c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt @@ -16,11 +16,11 @@ package org.jetbrains.kotlin.js.translate.intrinsic.objects -import org.jetbrains.kotlin.js.backend.ast.JsExpression -import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.builtins.CompanionObjectMapping import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.js.backend.ast.JsExpression +import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.StaticContext import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -29,10 +29,10 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe -class DefaultClassObjectIntrinsic(val staticContext: StaticContext, val fqName: FqName): ObjectIntrinsic { +class DefaultClassObjectIntrinsic(val staticContext: StaticContext, val tag: String, val fqName: FqName): ObjectIntrinsic { private val innerName: JsName by lazy { val declaration = JsAstUtils.replaceRootReference(staticContext.getQualifiedReference(fqName), Namer.kotlinObject()) - staticContext.importDeclaration(fqName.shortName().asString(), declaration) + staticContext.importDeclaration(fqName.shortName().asString(), tag, declaration) } override fun apply(context: TranslationContext) = JsAstUtils.pureFqn(innerName, null) @@ -53,7 +53,8 @@ class ObjectIntrinsics(private val staticContext: StaticContext) { val containingDeclaration = classDescriptor.containingDeclaration val name = Name.identifier(containingDeclaration.name.asString() + "CompanionObject") - return DefaultClassObjectIntrinsic(staticContext, FqName("kotlin.js.internal").child(name)) + return DefaultClassObjectIntrinsic( + staticContext, "intrinsic:kotlin.js.internal.${name.asString()}", FqName("kotlin.js.internal").child(name)) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/signatureUtils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/signatureUtils.kt index f987b536532..7a7fc465792 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/signatureUtils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/signatureUtils.kt @@ -34,7 +34,7 @@ fun generateSignature(descriptor: DeclarationDescriptor): String? { if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) return null if (descriptor is DeclarationDescriptorWithVisibility && descriptor.visibility == Visibilities.PRIVATE && !AnnotationsUtils.isNativeObject(descriptor) && !AnnotationsUtils.isLibraryObject(descriptor) - ) { + ) { return null } return when (descriptor) {