From feb968e66de6ee70891347e2fdc9f76a5885712e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 21 Apr 2017 15:12:24 +0300 Subject: [PATCH] JS: fix generation of names for local declarations Local declarations obtain names prefixed with outer function's name. Only simple name (i.e. without mangling) of outer function used in this case. This raises a problem in case of inline functions with object literals. Currently, they are not copied, but exported from module. Consider two inline functions foo with different signatures, both declare object literals. In this case both literals are exported as foo$f, so only one will be accessible from outside. --- .../kotlin/js/naming/NameSuggestion.kt | 22 ++++++++++------ .../js/test/semantics/BoxJsTestGenerated.java | 6 +++++ .../anonymousObjectInSimilarFunctions.kt | 25 +++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 js/js.translator/testData/box/inlineMultiFile/anonymousObjectInSimilarFunctions.kt diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index 5d6985fb0fd..e6910941aff 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -170,15 +170,21 @@ class NameSuggestion { } val fixedDescriptor = current - do { - parts += getSuggestedName(current) - val last = current + parts += if (fixedDescriptor is ConstructorDescriptor) { current = current.containingDeclaration!! - if (last is ConstructorDescriptor && !last.isPrimary) { - parts[parts.lastIndex] = getSuggestedName(current) + "_init" - current = current.containingDeclaration!! - } - } while (current is FunctionDescriptor) + getSuggestedName(current) + "_init" + } + else { + getSuggestedName(fixedDescriptor) + } + if (current.containingDeclaration is FunctionDescriptor && current !is TypeParameterDescriptor) { + val outerFunctionName = suggest(current.containingDeclaration as FunctionDescriptor)!! + parts += outerFunctionName.names.single() + current = outerFunctionName.scope + } + else { + current = current.containingDeclaration!! + } // Getters and setters have generation strategy similar to common declarations, except for they are declared as // members of classes/packages, not corresponding properties. 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 bc11a42ee42..a644260e76d 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 @@ -4421,6 +4421,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/inlineMultiFile"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("anonymousObjectInSimilarFunctions.kt") + public void testAnonymousObjectInSimilarFunctions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiFile/anonymousObjectInSimilarFunctions.kt"); + doTest(fileName); + } + @TestMetadata("anonymousObjectOnCallSite.kt") public void testAnonymousObjectOnCallSite() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiFile/anonymousObjectOnCallSite.kt"); diff --git a/js/js.translator/testData/box/inlineMultiFile/anonymousObjectInSimilarFunctions.kt b/js/js.translator/testData/box/inlineMultiFile/anonymousObjectInSimilarFunctions.kt new file mode 100644 index 00000000000..f2ab8eb8762 --- /dev/null +++ b/js/js.translator/testData/box/inlineMultiFile/anonymousObjectInSimilarFunctions.kt @@ -0,0 +1,25 @@ +// FILE: a.kt + +inline fun foo(x: String): I = object : I { + override fun get(): String = "foo_String($x)" +} + +// FILE: b.kt +inline fun foo(x: Int): I = object : I { + override fun get(): String = "foo_Int($x)" +} + +// FILE: main.kt +interface I { + fun get(): String +} + +fun box(): String { + val a = foo("1").get() + if (a != "foo_String(1)") return "fail1: $a" + + val b = foo(2).get() + if (b != "foo_Int(2)") return "fail2: $b" + + return "OK" +} \ No newline at end of file