From 7a156e440788a43e37cfc256ce12ab7505bcfb57 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 11 Oct 2017 14:07:34 +0300 Subject: [PATCH] Give unique names to fields for captured local functions When a local function is captured, corresponding field accesses are later transformed by the inliner. It doesn't have enough information to restore the original semantics completely, so it has to rely on field names. Local functions can be overloaded or can have names matching local variable names, in both cases we generated fields with the same name for captured values. Now, we use the same '$' suffix for field names for local functions as it is present in the corresponding local class name. This allows to distinguish captured local functions from captured local variables and between different overloads of a function with the same name. #KT-19827 Fixed #KT-18639 Fixed --- .../kotlin/codegen/context/LocalLookup.java | 11 +++- .../localFunctionVsLocalVariable.kt | 19 +++++++ .../overloadedLocalFunWithoutClosure.kt | 8 +++ .../localFunctions/overloadedLocalFunction.kt | 18 ++++++ .../overloadedLocalFunction1.kt | 23 ++++++++ .../overloadedLocalFunction2.kt | 23 ++++++++ .../overloadedLocalFunction3.kt | 21 +++++++ .../localFunctions/parameterAsDefaultValue.kt | 0 .../ir/IrBlackBoxCodegenTestGenerated.java | 57 ++++++++++++++----- .../codegen/BlackBoxCodegenTestGenerated.java | 57 ++++++++++++++----- .../LightAnalysisModeTestGenerated.java | 57 ++++++++++++++----- .../semantics/JsCodegenBoxTestGenerated.java | 57 ++++++++++++++----- 12 files changed, 289 insertions(+), 62 deletions(-) create mode 100644 compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt create mode 100644 compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt create mode 100644 compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt create mode 100644 compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt create mode 100644 compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt create mode 100644 compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt rename compiler/testData/codegen/box/{ => functions}/localFunctions/parameterAsDefaultValue.kt (100%) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java index eb2331375d1..43eff476b21 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java @@ -106,14 +106,21 @@ public interface LocalLookup { BindingContext bindingContext = state.getBindingContext(); Type localType = asmTypeForAnonymousClass(bindingContext, vd); - MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd)); + ClassDescriptor callableClass = bindingContext.get(CLASS_FOR_CALLABLE, vd); + assert callableClass != null : "No CLASS_FOR_CALLABLE:" + vd; + + MutableClosure localFunClosure = bindingContext.get(CLOSURE, callableClass); if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) { // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance // (instead of passing this instance to the constructor and storing as a field) return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd); } - String fieldName = "$" + vd.getName(); + String localFunClassName = callableClass.getName().asString(); + int localClassIndexStart = localFunClassName.lastIndexOf('$'); + String localFunSuffix = localClassIndexStart >= 0 ? localFunClassName.substring(localClassIndexStart) : ""; + + String fieldName = "$" + vd.getName() + localFunSuffix; StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false, StackValue.LOCAL_0, vd); diff --git a/compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt b/compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt new file mode 100644 index 00000000000..df58363773a --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt @@ -0,0 +1,19 @@ +fun box(): String { + var s = "" + var foo = "O" + + fun foo(x: String) { + s += x + } + + fun foo() { + foo("K") + } + + run { + foo(foo) // 1st foo is a local fun, second is a captured local var + foo() + } + + return s +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt new file mode 100644 index 00000000000..078f029fe75 --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt @@ -0,0 +1,8 @@ +fun box(): String { + fun foo(x: String) = x + fun foo() = foo("K") + + return run { + foo("O") + foo() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt new file mode 100644 index 00000000000..6e349f27ae9 --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt @@ -0,0 +1,18 @@ +fun box(): String { + var s = "" + + fun foo(x: String) { + s += x + } + + fun foo() { + foo("K") + } + + run { + foo("O") + foo() + } + + return s +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt new file mode 100644 index 00000000000..79645a8716d --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt @@ -0,0 +1,23 @@ +fun box(): String { + var s = "" + var foo = "K" + + fun foo(x: String, y: Int) { + s += x + } + + fun test() { + fun foo(x: String) { + s += x + } + + run { + foo("O") + foo(foo, 1) + } + } + + test() + + return s +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt new file mode 100644 index 00000000000..1cf01ce4e21 --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt @@ -0,0 +1,23 @@ +fun box(): String { + var s = "" + var foo = "K" + + fun foo(x: String, y: Int) { + s += x + } + + fun test() { + fun foo(x: String) { + s += x + } + + { + foo("O") + foo(foo, 1) + }() + } + + test() + + return s +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt new file mode 100644 index 00000000000..9504e6ebfac --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt @@ -0,0 +1,21 @@ +fun box(): String { + var s = "" + var foo = "O" + + fun foo(x: String, z: Int) { + s += x + } + + run { + fun foo(x: String) { + s += x + } + + { + foo(foo, 1) + foo("K") + } () + } + + return s +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt b/compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt similarity index 100% rename from compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt rename to compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index db686cc9a06..4596b1f4f51 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -9336,6 +9336,48 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt"); doTest(fileName); } + + @TestMetadata("localFunctionVsLocalVariable.kt") + public void testLocalFunctionVsLocalVariable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunWithoutClosure.kt") + public void testOverloadedLocalFunWithoutClosure() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction.kt") + public void testOverloadedLocalFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction1.kt") + public void testOverloadedLocalFunction1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction2.kt") + public void testOverloadedLocalFunction2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction3.kt") + public void testOverloadedLocalFunction3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt"); + doTest(fileName); + } + + @TestMetadata("parameterAsDefaultValue.kt") + public void testParameterAsDefaultValue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt"); + doTest(fileName); + } } } @@ -11283,21 +11325,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } - @TestMetadata("compiler/testData/codegen/box/localFunctions") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class LocalFunctions extends AbstractIrBlackBoxCodegenTest { - public void testAllFilesPresentInLocalFunctions() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); - } - - @TestMetadata("parameterAsDefaultValue.kt") - public void testParameterAsDefaultValue() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt"); - doTest(fileName); - } - } - @TestMetadata("compiler/testData/codegen/box/mangling") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9167bf056f1..55ff62ab07e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -9336,6 +9336,48 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt"); doTest(fileName); } + + @TestMetadata("localFunctionVsLocalVariable.kt") + public void testLocalFunctionVsLocalVariable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunWithoutClosure.kt") + public void testOverloadedLocalFunWithoutClosure() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction.kt") + public void testOverloadedLocalFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction1.kt") + public void testOverloadedLocalFunction1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction2.kt") + public void testOverloadedLocalFunction2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction3.kt") + public void testOverloadedLocalFunction3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt"); + doTest(fileName); + } + + @TestMetadata("parameterAsDefaultValue.kt") + public void testParameterAsDefaultValue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt"); + doTest(fileName); + } } } @@ -11283,21 +11325,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } - @TestMetadata("compiler/testData/codegen/box/localFunctions") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class LocalFunctions extends AbstractBlackBoxCodegenTest { - public void testAllFilesPresentInLocalFunctions() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); - } - - @TestMetadata("parameterAsDefaultValue.kt") - public void testParameterAsDefaultValue() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt"); - doTest(fileName); - } - } - @TestMetadata("compiler/testData/codegen/box/mangling") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 0373b3d7d5a..2a6c275aa94 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -9336,6 +9336,48 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt"); doTest(fileName); } + + @TestMetadata("localFunctionVsLocalVariable.kt") + public void testLocalFunctionVsLocalVariable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunWithoutClosure.kt") + public void testOverloadedLocalFunWithoutClosure() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction.kt") + public void testOverloadedLocalFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction1.kt") + public void testOverloadedLocalFunction1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction2.kt") + public void testOverloadedLocalFunction2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction3.kt") + public void testOverloadedLocalFunction3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt"); + doTest(fileName); + } + + @TestMetadata("parameterAsDefaultValue.kt") + public void testParameterAsDefaultValue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt"); + doTest(fileName); + } } } @@ -11283,21 +11325,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } - @TestMetadata("compiler/testData/codegen/box/localFunctions") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class LocalFunctions extends AbstractLightAnalysisModeTest { - public void testAllFilesPresentInLocalFunctions() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); - } - - @TestMetadata("parameterAsDefaultValue.kt") - public void testParameterAsDefaultValue() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt"); - doTest(fileName); - } - } - @TestMetadata("compiler/testData/codegen/box/mangling") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 490a6df830c..3937bd793c1 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -10188,6 +10188,48 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt"); doTest(fileName); } + + @TestMetadata("localFunctionVsLocalVariable.kt") + public void testLocalFunctionVsLocalVariable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/localFunctionVsLocalVariable.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunWithoutClosure.kt") + public void testOverloadedLocalFunWithoutClosure() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunWithoutClosure.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction.kt") + public void testOverloadedLocalFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction1.kt") + public void testOverloadedLocalFunction1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction2.kt") + public void testOverloadedLocalFunction2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction2.kt"); + doTest(fileName); + } + + @TestMetadata("overloadedLocalFunction3.kt") + public void testOverloadedLocalFunction3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/overloadedLocalFunction3.kt"); + doTest(fileName); + } + + @TestMetadata("parameterAsDefaultValue.kt") + public void testParameterAsDefaultValue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/localFunctions/parameterAsDefaultValue.kt"); + doTest(fileName); + } } } @@ -12483,21 +12525,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } - @TestMetadata("compiler/testData/codegen/box/localFunctions") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class LocalFunctions extends AbstractJsCodegenBoxTest { - public void testAllFilesPresentInLocalFunctions() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); - } - - @TestMetadata("parameterAsDefaultValue.kt") - public void testParameterAsDefaultValue() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localFunctions/parameterAsDefaultValue.kt"); - doTest(fileName); - } - } - @TestMetadata("compiler/testData/codegen/box/mangling") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)