diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index d135100abb8..835e20bb9bd 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -5678,6 +5678,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("localFunctions.kt") + public void testLocalFunctions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/nameClashes/localFunctions.kt"); + doTest(fileName); + } + @TestMetadata("methodAndPrivateProperty.kt") public void testMethodAndPrivateProperty() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/nameClashes/methodAndPrivateProperty.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt index e6467d7640a..5e7609d16cd 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.js.translate.expression -import org.jetbrains.kotlin.backend.common.SUSPENDED_MARKER_NAME import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl @@ -24,10 +23,10 @@ import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.* import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda import org.jetbrains.kotlin.js.inline.util.getInnerFunction +import org.jetbrains.kotlin.js.inline.util.rewriters.NameReplacingVisitor import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor import org.jetbrains.kotlin.js.translate.context.hasCapturedExceptContaining -import org.jetbrains.kotlin.js.translate.context.isCaptured import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments @@ -73,21 +72,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato val tracker = functionContext.usageTracker()!! - val isRecursive = tracker.isCaptured(descriptor) - - lambda.name = if (isRecursive) { - tracker.getNameForCapturedDescriptor(descriptor) - } - else { - invokingContext.getInnerNameForDescriptor(descriptor) - } - if (tracker.hasCapturedExceptContaining()) { val lambdaCreator = simpleReturnFunction(invokingContext.scope(), lambda) lambdaCreator.name = invokingContext.getInnerNameForDescriptor(descriptor) lambdaCreator.isLocal = true - if (!isRecursive || descriptor.isCoroutineLambda) { - lambda.name = null + if (descriptor in tracker.capturedDescriptors && !descriptor.isCoroutineLambda) { + lambda.name = tracker.getNameForCapturedDescriptor(descriptor) } lambdaCreator.name.staticRef = lambdaCreator lambdaCreator.fillCoroutineMetadata(invokingContext, descriptor, continuationType) @@ -95,6 +85,14 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato invokingContext) } + lambda.name = invokingContext.getInnerNameForDescriptor(descriptor) + if (descriptor in tracker.capturedDescriptors) { + val capturedName = tracker.getNameForCapturedDescriptor(descriptor)!! + val globalName = invokingContext.getInnerNameForDescriptor(descriptor) + val replacingVisitor = NameReplacingVisitor(mapOf(capturedName to JsAstUtils.pureFqn(globalName, null))) + replacingVisitor.accept(lambda) + } + lambda.isLocal = true invokingContext.addDeclarationStatement(lambda.makeStmt()) diff --git a/js/js.translator/testData/box/nameClashes/localFunctions.kt b/js/js.translator/testData/box/nameClashes/localFunctions.kt new file mode 100644 index 00000000000..c7ec5292819 --- /dev/null +++ b/js/js.translator/testData/box/nameClashes/localFunctions.kt @@ -0,0 +1,43 @@ +var log = "" + +fun foo() { + fun local(x: String) { + if (x.isEmpty()) return + log += "foo(${x[0]});" + local(x.substring(1)) + } + local("OK") +} + +fun bar() { + fun local(x: String) { + if (x.isEmpty()) return + log += "bar(${x[0]});" + local(x.substring(1)) + } + local("OK") +} + +fun baz(): Int { + fun local(x: String) { + if (x.isEmpty()) return + log += "baz(${x[0]});" + local(x.substring(1)) + } + fun local(x: Int): Int = if (x == 0) 1 else x * local(x - 1) + local("OK") + return local(3) +} + + +fun box(): String { + foo() + bar() + val result = baz() + + if (result != 6) return "fail1: $result" + + if (log != "foo(O);foo(K);bar(O);bar(K);baz(O);baz(K);") return "fail2: $result" + + return "OK" +} \ No newline at end of file