JS: when recursive local function does not capture variables, give it name from top-level scope. See KT-15770
This commit is contained in:
committed by
Alexey Andreev
parent
70d2296e61
commit
ac0df8eef9
@@ -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");
|
||||
|
||||
+11
-13
@@ -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())
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user