diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InliningScope.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InliningScope.kt index 3f6c3cbf73d..ca6fd420a72 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InliningScope.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InliningScope.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.localAlias import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef import org.jetbrains.kotlin.js.inline.clean.removeUnusedFunctionDefinitions import org.jetbrains.kotlin.js.inline.clean.removeUnusedImports +import org.jetbrains.kotlin.js.inline.clean.renameLabels import org.jetbrains.kotlin.js.inline.clean.simplifyWrappedFunctions import org.jetbrains.kotlin.js.inline.util.* import org.jetbrains.kotlin.js.translate.declaration.transformSpecialFunctionsToCoroutineMetadata @@ -162,6 +163,7 @@ class ProgramFragmentInliningScope( simplifyWrappedFunctions(allCode) removeUnusedFunctionDefinitions(allCode, collectNamedFunctions(allCode)) removeUnusedImports(fragment, allCode) + renameLabels(allCode) } override fun hasImport(name: JsName, tag: String): JsName? { diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/renameLabels.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/renameLabels.kt new file mode 100644 index 00000000000..37bf730fdf9 --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/renameLabels.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.js.inline.clean + +import org.jetbrains.kotlin.js.backend.ast.* + +fun renameLabels(root: JsNode) { + // Labels in JS are in separate scope from local variables. It's only important that nested labels don't clash. + // Adjacent labels in one function is OK + root.accept(object : RecursiveJsVisitor() { + val replacements = mutableMapOf() + + var labels = mutableSetOf() + + override fun visitElement(node: JsNode) { + super.visitElement(node) + if (node is HasName) { + val name = node.name + if (name != null) { + replacements[name]?.let { node.name = it } + } + } + } + + override fun visitLabel(x: JsLabel) { + var addedName: String? = null + if (x.name.isTemporary) { + var resolvedName = x.name.ident + var suffix = 0 + while (!labels.add(resolvedName)) { + resolvedName = "${x.name.ident}_${suffix++}" + } + replacements[x.name] = JsDynamicScope.declareName(resolvedName) + addedName = resolvedName + } + super.visitLabel(x) + addedName?.let { + labels.remove(it) + } + } + + override fun visitFunction(x: JsFunction) { + val oldLabels = labels + labels = mutableSetOf() + super.visitFunction(x) + labels = oldLabels + } + }) +} \ No newline at end of file diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/resolveTemporaryNames.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/resolveTemporaryNames.kt index dc3ac9ba8cd..4b8d3dcf29d 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/resolveTemporaryNames.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/resolveTemporaryNames.kt @@ -62,36 +62,6 @@ private fun JsNode.resolveNames(): Map { traverse(rootScope) - // Labels in JS are in separate scope from local variables. It's only important that nested labels don't clash. - // Adjacent labels in one function is OK - accept(object : RecursiveJsVisitor() { - var labels = mutableSetOf() - - override fun visitLabel(x: JsLabel) { - var addedName: String? = null - if (x.name.isTemporary) { - var resolvedName = x.name.ident - var suffix = 0 - while (!labels.add(resolvedName)) { - resolvedName = "${x.name.ident}_${suffix++}" - } - replacements[x.name] = JsDynamicScope.declareName(resolvedName) - addedName = resolvedName - } - super.visitLabel(x) - addedName?.let { - labels.remove(it) - } - } - - override fun visitFunction(x: JsFunction) { - val oldLabels = labels - labels = mutableSetOf() - super.visitFunction(x) - labels = oldLabels - } - }) - return replacements } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ast/NameResolutionTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ast/NameResolutionTest.kt index e706644556f..e20541fb310 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ast/NameResolutionTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ast/NameResolutionTest.kt @@ -20,6 +20,7 @@ import com.google.gwt.dev.js.rhino.CodePosition import com.google.gwt.dev.js.rhino.ErrorReporter import com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.js.backend.ast.* +import org.jetbrains.kotlin.js.inline.clean.renameLabels import org.jetbrains.kotlin.js.inline.clean.resolveTemporaryNames import org.jetbrains.kotlin.js.parser.parse import org.jetbrains.kotlin.js.test.BasicBoxTest @@ -69,21 +70,21 @@ class NameResolutionTest { node.name = node.name?.let { name -> if (name.ident.startsWith("$")) { cache.getOrPut(name) { JsScope.declareTemporaryName("x") } - } - else { + } else { name } } } } }) + renameLabels(originalAst) originalAst.resolveTemporaryNames() assertEquals(expectedAst.toString(), originalAst.toString()) } private val errorReporter = object : ErrorReporter { - override fun warning(message: String, startPosition: CodePosition, endPosition: CodePosition) { } + override fun warning(message: String, startPosition: CodePosition, endPosition: CodePosition) {} override fun error(message: String, startPosition: CodePosition, endPosition: CodePosition) { fail("Error parsing JS file: $message at $startPosition") 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 88be9d934f1..66395110b86 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 @@ -241,7 +241,7 @@ class Merger( // TODO better placing? val additionalFakeOverrides = mutableListOf() - importedFunctionWrappers.values.forEach {block -> + importedFunctionWrappers.values.forEach { block -> block.statements.forEach { s -> if (s.isFakeOverrideAssignment()) { additionalFakeOverrides += s